Sei sulla pagina 1di 42

PR1

Lezione 8:
I puntatori

Michele Nappi
mnappi@unisa.it

02/05/19 1
Introduzione

• I puntatori
– Una delle caratteristiche più potenti del C, ma
difficile da padroneggiare
– Si usano per simulare la chiamata per
riferimento
– Stretta correlazione con vettori e stringhe

02/05/19 2
Dichiarazione e inizializzazione
di una variabile puntatore
• Le variabili puntatore
– Contengono indirizzi come valori
– Le variabili normali contengono uno specifico valore
(riferimento diretto) count
7

– I puntatori contengono l’indirizzo di una variabile che


ha uno specifico valore (riferimento indiretto)
countPtr count
7

– Deriferimento - riferimento a un valore per mezzo di


un puntatore
02/05/19 3
Dichiarazione e inizializzazione di una
variabile puntatore (II)

• Il tipo puntatore è un classico esempio di tipo


derivato: infatti non ha senso parlare di tipo puntatore
in generale, ma occorre sempre specificare a quale
tipo esso punta.
Dichiarazione di una variabile riferimento o
puntatore
tipo_base *var_punt;
dove tipo_base è uno dei tipi fondamentali già introdotti:
char, int, float e double.
var_punt è definita come una variabile di tipo puntatore a
tipo_base
var_punt è creata per mantenere l’indirizzo di variabili di tipo
tipo_base

02/05/19 4
Dichiarazione e inizializzazione
di una variabile puntatore (III)
• Dichiarazioni di puntatori
– * usato con variabili puntatore
int *myPtr;
– Dichiara un puntatore a un valore di tipo int
(si legge “myPtr è un puntatore a tipo int”)
– Puntatori multipli richiedono * multipli
int *myPtr1, *myPtr2;
– E’ possibile dichiarare puntatori a qualsiasi tipo di dato
– I puntatori possono essere inizializzati a 0, a NULL (costante
simbolica definita in molti file di intestazione) oppure a un
indirizzo
• 0 o NULL - non fa riferimento a nessun dato (si preferisce
NULL)
02/05/19 5
Inizializzazione Puntatori
• & (operatore di indirizzo)
– Restituisce l’indirizzo dell’operando
int y = 5;
int *yptr;
yptr = &y; //a yPtr viene assegnato l’indirizzo di y
– yPtr “punta a” y
y yptr y
5 500000 600000 600000 5
yPtr

L’indirizzo di
y è il valore di
yptr

02/05/19 6
Nota
• L’operando dell’operatore di indirizzo (&)
deve essere una variabile
&x /*x deve essere una variabile*/

• La & non può essere applicato a costanti,


a espressioni o a variabili dichiarate con la
specifica di classe di memoria register

02/05/19 7
Operatori sui Puntatori
• * (operatore di deriferimento o di risoluzione del
riferimento)
– Restituisce il valore dell’oggetto puntato dal suo operando (che è un
puntatore)
int y = 5, x;
int *yPtr;
yPtr = &y;
x = *yptr;
*yptr restituisce il valore di y (perché yptr punta a y)
Questa utilizzazione di * è detta risoluzione del
riferimento di un puntatore
– * può essere usato per l’assegnamento
*yptr = 7; // modifica y in 7

02/05/19 8
Esempio
int a;
char c;
int *pi; /*pi è una variabile di tipo puntatore a int */
char *pc; /* pc è una variabile di tipo puntatore a char */
pi = &a; /* pi è inizializzata con l’indirizzo di a */
pc = &c; /* pc è inizializzata con l’indirizzo di c */
a = 5;
c = ‘x’;

int a;
char c;
a=?
c =?
int *pi; pi = ?
char *pc; pc =?
pi = &a;
pc = &c; pi =
pc =
a = 5; */ ora pi punta all’intero 5 /*
c = ‘x’; */ ora pc punta al carattere ‘x’ */

02/05/19 9
Operatori sui Puntatori
• * e & sono l’uno l’inverso dell’altro
– Essi si annullano l’un l’altro

*&yptr -> * (&yptr) -> * (indirizzo di yptr)->


restituisce l’alias di ciò a cui punta l’operando
-> yptr
yptr y
500000 600000 600000 5

*&yptr punta al valore contenuto nell’indirizzo di


yptr e cioè al valore contenuto nell’indirizzo 500000,
e cioè proprio yptr (600000 in questo caso)
Analogamente:
&*yptr -> &(*yptr) -> &(y) -> restituisce
02/05/19l’indirizzo di y, che è yptr -> yptr 10
Riassumendo su & e *
• L’operatore & ha significato “indirizzo di”,
infatti &x si legge “indirizzo di x”

• L’operatore * ha tre significati diversi:


1. Operatore di moltiplicazione 5*x
2. Dichiarazione di puntatore int *x
3. Operatore di de-riferimento *y
e va applicato a variabili puntatori

02/05/19 11
Gli indirizzi come dati

p è un indirizzo di interi
int main (void)
{ x è un indirizzo di double
int i, *p;
a p è assegnato l’indirizzo di i
double *x, y;
i = 12 *p è l’operazione di dereferenziazione
p = &i;
i = *p + 9; nessun problema: conversione
y = *p + 1; automatica di tipo
x = p;
return 0; Errore: x e p sono entrambi indirizzi, ma
} di tipo diverso

02/05/19 12
Il valore NULL
Errore: p non è stata inizializzata: la sua
dereferenziazione non ha senso!
int main (void) NULL è una costante definita nella
{ libreria stdlib.h che viene inclusa
automaticamente con #include <stdio.h>
int *p;
*p = 7;
p = NULL; Errore: un puntatore NULL non può
essere dereferenziato!
*p = 0;
return 0;
}

02/05/19 13
Specifica di conversione %p
La specifica di conversione %p restituisce la locazione di memoria cui si
riferisce, convertendola in un formato definito dall’implementazione
(molto spesso un intero esadecimale)
int *ptr;
int x = 1123;
ptr = &x;
printf(“l’indirizzo di x è %p\n”,
&x);
printf(“il valore di ptr è%p\n”,
ptr);

l’indirizzo di x è 001F2BB4
il valore di ptr è 001F2BB4

02/05/19 14
1 /* Fig. 7.4: fig07_04.c
2 Uso degli operatori & e * */
3 #include <stdio.h>
4
5 int main()
6 { L’indirizzo di a è il valore di
7 int a; /* a è un intero */ aPtr.
8 int *aPtr; /* aPtr è un puntatore a un intero */
9
10 a = 7; L’operatore * restituisce ciò
11 aPtr = &a; /* aPtr viene inizializzato a cuidipunta
all’indirizzo a */l’operando.
12 aPtr punta ad a, così
13 printf( ”L’indirizzo di a è %p"
*aPtr restituisce a.
14 "\Il valore di aPtr è %p", &a, aPtr );
15
16 printf( "\n\nIl valore di a è %d"
17 "\nIl valore di *aPtr è %d", a, *aPtr );
18
19 printf( "\n\nDimostrazione che * e & sono l’uno " Si noti come * e
20 ”inverso dell’altro.\n&*aPtr = %p" & sono inversi
21 "\n*&aPtr = %p\n", &*aPtr, *&aPtr );
22
23 return 0;
24 }
L’indirizzo di a è 0012FF88
Il valore di aPtr è 0012FF88

Il valore di a è 7
Il valore di *aPtr è 7
Dimostrazione che * e & sono l’uno l’inverso dell’altro.
&*aPtr = 0012FF88
02/05/19 15
*&aPtr = 0012FF88
Esercizio

Scrivere un programma, che dato un array di 100 numeri


interi, assegna un valore a due variabili puntatore che
puntano all’elemento dell’array contenente,
rispettivamente, il valore più basso e il valore più alto.

02/05/19 16
#define DIM_ARRAY 100
main ( )
{ */ dichiarazione di variabili */
int i;
int array[DIM_ARRAY];
int *punta_a_minore;
int *punta_a_maggiore;
punta_a_minore = &array[0];
i = 1;
while (i< DIM_ARRAY)
{
if (array[i] < *punta_a_minore)
punta_a_minore = &array[i];
i = i+1;
}

punta_a_maggiore = &array[0];
i = 1;
while (i< DIM_ARRAY)
{
if (array[i] > *punta_a_maggiore)
punta_a_maggiore = &array[i];
i = i+1;
}
}

02/05/19 17
La chiamata per riferimento delle funzioni

• Chiamata per riferimento con puntatori come argomenti


– Si passa l’indirizzo dell’argomento usando l’operatore &
– Consente di fare modifiche alla reale locazione di memoria
che contiene il valore passato dalla funzione chiamante.
– Gli array non sono passati con & poiché il nome dell’array
è già un puntatore (arrayName equivale a &arrayName[0])
• L’operatore *
– E’ usato come alias/soprannome per la variabile all’interno
della funzione
void double(int *number) /* number conterrà un indirizzo */
{
*number = 2 * (*number); /* *number contiene un intero */
}
*number è usato come alias per la variabile passata

02/05/19 18
A confronto due programmi che calcolano il cubo di un intero :
chiamata per valore Vs. chiamata per riferimento
1 /* Fig. 7.6: fig07_06.c
2 Cube a variable using call-by-value */
3 #include <stdio.h>
4
5 int cubeByValue( int ); /* prototype */
6
7 int main()
8 {
9 int number = 5;
10
11 printf( "The original value of number is %d", number );
12 number = cubeByValue( number );
13 printf( "\nThe new value of number is %d\n", number );
14
15 return 0;
16 }
17
18 int cubeByValue( int n )
19 {
20 return n * n * n; /* cube local variable n */
21 }

The original value of number is 5


The new value of number is 125

02/05/19 19
Prima della chiamata per valore a cubeByValue:
main() number int cubeByValue( int n )
{ {
int number = 5; 5 return n * n * n;
}
number = cubeByValue( number );
} n indefinito

Dopo la chiamata a cubeByValue:


main() int cubeByValue( int n )
{ number {
int number = 5; 5 return n * n * n;
}
number = cubeByValue( number );
} n 5

Dopo che cubeByValue fa il cubo del parametro n:

main() number int cubeByValue( int n )


{ { 125
int number = 5; 5 return n * n * n;
}
number = cubeByValue( number );
} n 5

02/05/19 20
Dopo che cubeByValue restutuisce il valore al main
main() number int cubeByValue( int n )
{ {
int number = 5; 5 return n * n * n;
125
}
number = cubeByValue( number );
} n indefinito

Dopo che main completa l’assegnazione a number:


main() int cubeByValue( int n )
{ number {
int number = 5; 125 return n * n * n;
}
number = cubeByValue( number );
} n indefinito

02/05/19 21
1 /* Fig. 7.7: fig07_07.c
2 Il cubo di una variabile usando una chiamata per riferimento
3 con un argomento puntatore */
4
5 #include <stdio.h>
6 Si noti come è dato l’indirizzo di
7 void cubeByReference( int * ); /* number -*/cubeByReference
prototype
8 si aspetta un puntatore (un
9 int main() indirizzo di variabile).
10 {
11 int number = 5;
12
13 printf( ”Il valore originale di number è %d", number );
14 cubeByReference( &number );
15 printf( "\Il nuovo valore di number è %d\n", number );
16 All’interno di
17 return 0; cubeByReference, è usato
18 } *nPtr (*nPtr is number).
19
20 void cubeByReference( int *nPtr )
21 {
22 *nPtr = *nPtr * *nPtr * *nPtr; /* il cubo di number nel main */
23 }

Il valore originale di number è 5


Il nuovo valore di number è 125

02/05/19 22
Prima della chiamata per riferimento a cubeByReference:
main() number cubeByReference( int *nPtr )
{ {
int number = 5; 5 *nPtr = *nPtr * *nPtr * *nPtr;
}
cubeByReference( &number );
} nPtr indefinito

Dopo la chiamata per riferimento a cubeByReference e prima che venga fatto il cubo di *nPtr:
main() cubeByReference( int *nPtr )
{ number {
int number = 5; 5 *nPtr = *nPtr * *nPtr * *nPtr;
}
cubeByReference( &number );
} nPtr

Dopo che *nPtr è stato moltiplicato al cubo:

main() number cubeByReference( int *nPtr )


{ {
int number = 5; 125 *nPtr = *nPtr * *nPtr * *nPtr;
}
cubeByReference( &number );
} nPtr

02/05/19 23
Chiamata per riferimento delle funzioni
(Sintesi)

• Supponiamo che la variabile x di tipo int debba essere


passata per riferimento ad una funzione foo:
– Nella chiamata alla funzione foo si passa l’indirizzo di x usando
l’operatore &
foo(&x)
– Nella definizione della funzione:
• Il parametro deve essere un puntatore ptr
Es. void foo(int *ptr)

• Nel corpo si utilizza l’operatore di deriferimento *


Es. *ptr = 5;

02/05/19 24
Chiamata per riferimento delle funzioni
Sintesi (II)
• Se dobbiamo passare un array a ad una funzione foo:
• Ricordiamo che
– a è equivalente a &a[0]
– Cioè a è un puntatore
– int *a è equivalente a int a[]
• Quindi:
– Nella chiamata alla funzione foo non si utilizza l’operatore & poiché il
nome dell’array è già un indirizzo
foo(a)
– Nella definizione della funzione:
• Il parametro deve essere un array
void foo(int array[]) oppure void foo(int *array)
• Nel corpo non si utilizza l’operatore di deriferimento *
Es. array[3] = 5;
02/05/19 25
Espressioni con i puntatori e
aritmetica dei puntatori
• Sui puntatori è possibile eseguire operazioni aritmetiche
– Incremento/decremento del puntatore (++ opp. --)
– Aggiungere o sottrarre un intero a un puntatore ( +
opp. += , - opp. -=)
– Si può sottrarre un puntatore da un altro puntatore

Le operazioni aritmetiche sui puntatori hanno significato


solo se eseguite su un vettore
Infatti solo in quel caso si può essere sicuri di operare su
oggetti immagazzinati in locazioni di memoria consecutive

02/05/19 26
Espressioni con i puntatori
e aritmetica dei puntatori (II)
• Un array di 5 elementi int in una macchina che implementa gli
interi con 4 byte
– vPtr punta al primo elemento v[0]
alla locazione 3000. (vPtr = 3000) Potrà essere inizializzato
con una delle seguenti istruzioni
vPtr = &v[0];
vPtr = v;
– vPtr +=2; pone vPtr a 3008
•vPtr punta a v[2] (incrementato
di 2), ma la macchina ha int di 4 byte.

locazione
3000 3004 3008 3012 3016

v[0] v[1] v[2] v[3] v[4]

Variabile puntatore vPtr


02/05/19 27
Espressioni con i puntatori
aritmetica dei puntatori (III)
• Sottrazione tra puntatori
– Restituisce il numero di elementi compresi tra l’uno e
l’altro.
vPtr2 = &v[2];
vPtr = &v[0];
vPtr2 - vPtr = 2.

• Confronto tra puntatori ( <, == , > )


– Per esempio per vedere quale di due puntatori punta
all’elemento del vettore con l’indice più alto.
– Anche per vedere se un puntatore è NULL

02/05/19 28
Esercizio

Descrivere il comportamento della seguente porzione di codice.


int v1[10];
char v2[10];
char *p;
int a;
a = &v1[5] - &v1[3];
printf(“%d\n”, a);
a = &v1[5] - &v2[3];
printf(“%d\n”, a);
p = v2 + 2;
printf(“%d\n”, *p);

02/05/19 29
Soluzione

int v1[10];
char v2[10];
char *p;
int a;
a = &v1[5] - &v1[3];
*/ sottrazione tra indirizzi dello stesso array */
printf(“%d\n”, a); */ stampa 2 */
a = &v1[5] - &v2[3];
*/ sottrazione tra indirizzi di array diversi */
printf(“%d\n”, a); */ il risultato non è prevedibile */
p = v2 + 2;*/addizione di una costante da un indirizzo */
printf(“%d\n”, *p);
*/ il puntatore p va a puntare a v2[2]
e ne stampa il contenuto */

02/05/19 30
Esercizio

Dire cosa stampa la seguente porzione di codice.


char v[4] = {‘m’, ‘e’, ‘l’, ‘a’};
char *p;
p = v;
v++;
printf(“%d\n”, *p);

02/05/19 31
Soluzione

char v[4] = {‘m’, ‘e’, ‘l’, ‘a’};


char *p;
p = v;
v++; */ errore: il valore di v è una costante e
non può essere cambiato */
printf(“%d\n”, *p);

02/05/19 32
Espressioni con i puntatori
e aritmetica dei puntatori (IV)
• E’ possibile assegnare un puntatore a un altro purché
dello stesso tipo.
– Se non sono dello stesso tipo si può applicare un
operatore di conversione per convertire il puntatore a
destra dell’assegnamento nel tipo di quello a sinistra.
– Eccezione: puntatore a void (tipo void *)
• Puntatore generico, che rappresenta qualsiasi tipo
• A una variabile puntatore a void può essere assegnato
qualsiasi tipo di puntatore (Nessuna conversione è
necessaria per convertire un puntatore in un puntatore a
void).
• Viceversa, un puntatore a void può essere assegnato a tutti
gli altri tipi di puntatori senza bisogno di conversioni.
• Non è possibile risolvere il riferimento di un puntatore a void.
02/05/19 33
La relazione tra puntatori e vettori

• I vettori e i puntatori sono strettamente correlati


– Il nome di un vettore può essere considerato come un
puntatore costante
– I puntatori potranno essere usati per svolgere
qualsiasi operazione che coinvolga gli indici di un
vettore.

• Supponiamo che sia stato dichiarato un vettore b[5] e un


puntatore bPtr.
bPtr = b;
Il nome del vettore è in realtà l’indirizzo del primo elemento
OPPURE
bPtr = &b[0]
Assegna esplicitamente a bPtr l’indirizzo del primo elemento
02/05/19 34
La relazione tra puntatori e vettori (II)

• Elemento b[n]
–Vi si può accedere tramite espressione con puntatore
*( bPtr + n )
–Il vettore stesso può usare l’aritmetica dei puntatori.
b[3] equivale a *(b + 3) e a *(bPtr + 3)
Anche l’indirizzo di un elemento di un vettore si può ottenere con la stessa
notazione:
&b[3] equivale a bPtr + 3
In generale tutte le espressioni con gli indici potranno
essere convertite in quelle con puntatore e offset
–I puntatori possono essere usati in combinazione con gli
indici esattamente come i vettori ( notazione con puntatore
e indice)
bPtr[3] punterà all’elemento b[3]
02/05/19 35
1 /* Fig. 7.20: fig07_20.cpp
2 Usare la notazione con indici e puntatori per i vettori */ Il vettore b stampato con
3
4 #include <stdio.h>
Notazione con indici di vettore
5 b[0] = 10
6 int main()
7 { b[1] = 20
8 int b[] = { 10, 20, 30, 40 }; b[2] = 30
9 int *bPtr = b; /* fa puntare bPtr al vettore b */
10 int i, offset; b[3] = 40
11 printf( ”Il vettore b stampato con:\n" Notazione con puntatore e offset dove
12 ”Notazione con indici di vettore\n" );
13 il puntatore è il nome del vettore
14 for ( i = 0; i < 4; i++ )
15 printf( "b[ %d ] = %d\n", i, b[ i ] );
*(b + 0) = 10
16 *(b + 1) = 20
17
18 printf( "\nNotazione con puntatore e offset dove\n"
*(b + 2) = 30
19 ”il puntatore è il nome del vettore\n" ); *(b + 3) = 40
20
21 for ( offset = 0; offset < 4; offset++ ) Notazione con puntatore e indice
22 printf( "*( b + %d ) = %d\n", offset, *( b + offset ) ); bPtr[0] = 10
23
24 bPtr[1] = 20
25 printf( "\nNotazione con puntatore e indice\n" ); bPtr[2] = 30
26
27 for ( i = 0; i < 4; i++ ) bPtr[3] = 40
28 printf( " bPtr[ %d ] = %d\n", i, bPtr[ i ] );
29
Notazione con puntatore e offset
30 printf( "\nNotazione con puntatore e offset \n" ); *(bPtr + 0) = 10
31
32 for ( offset = 0; offset < 4; offset++ )
*(bPtr + 1) = 20
33 printf( "*( bPtr + %d ) = %d\n", offset, *( bPtr + offset ) ); *(bPtr + 2) = 30
34
35 return 0; *(bPtr + 3) = 40
36 }

02/05/19 36
1 /* Fig. 7.21: fig07_21.cpp
2 Copiare una stringa usando la notazione con indici di vettore
3 e la notazione con puntatore. */
4 #include <stdio.h> Prototipi identici, eseguono lo
5 stesso compito ma hanno
6 void copy1( char *, char * );
7 void copy2( char *, char * ); implementazioni diverse
8
9 int main()
10 {
11 char string1[ 10 ], *string2 = "Hello",
12 string3[ 10 ], *string4 = "Good Bye";
13
14 copy1( string1, string2 );
15 printf( "string1 = %s\n", string1 );
16
17 copy2( string3, string4 );
18 printf( "string3 = %s\n", string3 );
19
20 return 0;
21 }
22
23 /* copia s2 in s1 usando la notazione con gli indici di vettore
*/
24 void copy1( char *s1, char *s2 )
25 {
26 int i;
27 for ( i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ );
28 /* il corpo del for è vuoto */
29 }
30
31 /* copia s2 in s1 usando la notazione con i puntatori */
32 void copy2( char *s1, char *s2 )
33 {
34 for ( ; ( *s1 = *s2 ) != '\0'; s1++, s2++ );
35 /* il corpo del for è vuoto */
36 }

02/05/19 37
1 /* Fig. 7.21: fig07_21.cpp
2 Copiare una stringa usando la notazione con indici di vettore
3 e la notazione con puntatore. */
4 #include <stdio.h> Prototipi identici, eseguono lo
5 stesso compito ma hanno
6 void copy1( char *, char * );
7 void copy2( char *, char * ); implementazioni diverse
8
9 int main()
10 {
11 char string1[ 10 ], *string2 = "Hello",
12 string3[ 10 ], *string4 = "Good Bye";
13
14 copy1( string1, string2 );
15 printf( "string1 = %s\n", string1 );
16
17 copy2( string3, string4 );
18 printf( "string3 = %s\n", string3 );
19
20 return 0;
21 }
22
23 /* copia s2 in s1 usando la notazione con gli indici di vettore
*/
24 void copy1( char *s1, char *s2 )
25 {
26 int i;
27 for ( i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ );
28 /* il corpo del for è vuoto */
29 }
30
31 /* copia s2 in s1 usando la notazione con i puntatori */
32 void copy2( char *s1, char *s2 )
33 {
34 for ( ; ( *s1 = *s2 ) != '\0'; s1++, s2++ );
35 /* il corpo del for è vuoto */
36 }

02/05/19 38
Array come puntatori
Così come gli elementi di un array vengono scanditi per mezzo
dell’indice, si può accedere agli elementi di un array per mezzo di
un puntatore (notazione con puntatore e offset).

Esempio: Cosa stampa ?


char tab [100];
char *s;
s = tab;
tab [7] = ‘a’;
printf (“tab [7] = %c\n”, tab[7]);
*(s+7) = ‘b’;
*/ incrementando di 7 il valore di s si ottiene un
valore corrispondente all’indirizzo dell’ottavo
elemento di tab, al quale si accede per mezzo
dell’operatore di deriferenziazione. Dunque, si può
far riferimento a tab[7] scrivendo *(s+7). */
printf (“tab [7] = %c\n”, tab[7]);
02/05/19 39
tab =
tab[0] = ?
char tab [100];
...
char *s;
tab[99] = ?
s=?

tab =
tab[0] = ?
s = tab;
...
tab [7] = ‘a’;
tab[7] = ‘a’
printf (“tab [7] = %c\n”, tab[7]);
...
tab[99] = ?
s=?

*(s+7) = ‘b’; ...


printf (“tab [7] = %c\n”, tab[7]); tab[7] = ‘b’
...

02/05/19 40
Vediamo come si può inizializzare un
array in due modi diversi.

Primo modo Secondo modo


char tab [100]; char tab [100];
int i; char * s;
for (i=0; i < 100; i++) int i;
tab[i] = ‘k’; s = tab;
for (i=0; i < 100; i++)
*s++ = ‘k’;

L’istruzione *s++ = ‘k’; opera nel seguente modo:


• copia k nella locazione di memoria puntata da s;
• poi incrementa s di un elemento.

02/05/19 41
Vettori di puntatori
• I vettori possono contenere dei puntatori - Es. vettore
di stringhe
char *suit[4] = {"Hearts", "Diamonds", "Clubs", "Spades" };
– Stringa: puntatore al primo carattere della stringa
– char * - ogni elemento di suit è un puntatore a un char
– Le stringhe non sono realmente nel vettore - soltanto i
puntatori alle stringhe sono nel vettore

suit[0] ’H’ ’e’ ’a’ ’r’ ’t’ ’s’ ’\0’

suit[1] ’D’ ’i’ ’a’ ’m’ ’o’ ’n’ ’d’ ’s’ ’\0’

suit[2] ’C’ ’l’ ’u’ ’b’ ’s’ ’\0’

suit[3] ’S’ ’p’ ’a’ ’d’ ’e’ ’s’ ’\0’

• Il vettore suit ha una dimensione fissa, ma le


stringhe possono essere di qualsiasi lunghezza.

02/05/19 42