I puntatori Puntatore Definizione Assegnazione

Transcript

I puntatori Puntatore Definizione Assegnazione
2
Puntatore

I puntatori

Ver. 2.4
E’ una variabile che contiene l’indirizzo di
memoria di un oggetto (variabile o costante)
Esempio
p è un puntatore e “punta”
12
A55
x
alla variabile x che in
...
A54
questo esempio ha indirizzo
...
di memoria A55)
A53
int x=12;
x:A55
...
A52
12
p
A55
A51
...
A50
A55
p
© 2010 - Claudio Fornaro - Corso di programmazione in C
3
Definizione


Sintassi
tipo *nomeVariabile;
Esempi
int *punt;
char x, *p, *q, y;
x e y sono variabili di tipo char
p e q sono variabili di tipo puntatore-a-char
4
Assegnazione



Ad un puntatore si possono assegnare solo
indirizzi di memoria o il valore NULL che indica
che il puntatore non punta a nulla
La costante 0 in un contesto dove è atteso un
puntatore (inizializzazione e assegnamento di
un puntatore, confronto con un puntatore)
viene convertita in NULL dal compilatore
L’operatore di indirizzo ‘&’ (“ampersand”)
calcola l’indirizzo di memoria di una variabile
(si dice che ne restituisce il puntatore)
int *p = &x; inizializza p con l’indirizzo di x
assegna a p l’indirizzo di y
p = &y;
5
Utilizzo



6
Utilizzo
Si accede all’oggetto puntato da un puntatore
per mezzo dell’operatore ‘*’ detto
operatore di deriferimento (“dereference”)
o di indirezione (“indirection”)
int x=12, *p = &x;  p “punta a” x
*p = 24;
 x ora vale 24
*p += 6;
 x ora vale 30
p è il puntatore
*p è l’oggetto puntato (qui è x)



Sia p sia *p sono L-value modificabili, ossia
sono un “qualcosa” (variabile, elemento di
vettore, …) a cui si può assegnare un valore
L’operatore ‘*’ ha priorità superiore a quella
degli operatori matematici
x = 6 * *p; equivale a: x = 6 * (*p);
Per visualizzare il valore di un puntatore si
può utilizzare la direttiva %p in una printf
Si noti che la sintassi per indicare l’oggetto
puntato e quella della definizione del puntatore
sono identiche: *p
7
Tipi e puntatori


L’informazione relativa al tipo è necessaria per
permettere ai puntatori di conoscere la
dimensione dell’oggetto puntato (usata
nell’aritmetica dei puntatori)
Poiché oggetti di tipo diverso possono avere
dimensione diversa, l’assegnazione tra
puntatori di tipo diverso è in genere errata e il
compilatore genera un warning
int *p, x=12;
long *q, y=26;
p = &x;  OK!
q = &y;  OK!
q = p;  NO! Warning
q = &x;  NO! Warning
8
Puntatori a void




Sono puntatori generici e non possono essere
dereferenziati (non si può scrivere *p),
possono essere utilizzati solo come contenitori
temporanei di valori di tipo puntatore (a
qualsiasi tipo)
void *h;
Non serve il cast (void *) per copiare un
puntatore non-void in un puntatore void
h = p; (supponendo ad esempio int *p)
Qualsiasi tipo di puntatore può essere
confrontato con un puntatore a void
NULL è definito come: (void *)0
9
Puntatori a void


10
Puntatori e vettori
Per dereferenziare il valore di un puntatore a
void è necessario assegnarlo ad un puntatore
al tipo appropriato (non void) per poter
conoscere la dimensione dell’oggetto puntato
Può essere necessario il cast (tipo *) per
copiare un puntatore void in un puntatore
non-void (i compilatori C non lo richiedono, i
compilatori C++ sì).
In riferimento all’esempio precedente:
int *q;
q = h;
 OK, compilatore C
q = (int *)h;  OK, compilatore C++
*q = 23;
 x ora contiene 23

Il nome (senza parentesi) di un vettore-di-T
è un valore costante di tipo puntatore-a-T,
corrisponde all’indirizzo di memoria del primo
elemento di vettore
int vett[100];
int *p;
p = vett;
l’indirizzo di memoria di vett viene messo in
p, equivale a scrivere: p = &vett[0] (le
parentesi hanno priorità maggiore di &)
11
Puntatori e vettori

Attenzione:
vett = p;  NO!
Non si può assegnare un valore a vett in
quanto NON è una variabile puntatore, ma un
“sinonimo” di un indirizzo di memoria
Gli indirizzi di memoria sono valori costanti
stabiliti dal compilatore, non sono variabili e
quindi non hanno uno spazio in memoria
modificabile per contenere un valore
Il termine “puntatore” viene comunemente (e
impropriamente) usato al posto di “indirizzo di
memoria” (es. “&a dà il puntatore ad a”)
12
Equivalenza puntatori e vettori


Una variabile di tipo puntatore-a-T, assegnata
in modo che punti a (cioè contenga l’indirizzo
di) un oggetto di tipo vettore-di-T , può essere
utilizzata come se fosse un vettore-di-T
int vett[25];
int *p = vett;
vett:
p
Ad esempio, qui p[3] equivale a vett[3]
Il compilatore internamente trasforma le
espressioni con notazione vettoriale [] in
espressioni con i puntatori
13
Aritmetica dei puntatori

Aritmetica dei puntatori
Quando un puntatore punta ad un vettore,
gli può essere sommato un valore intero N, il
risultato è l’indirizzo di memoria dell’elemento
di posizione N del vettore
vett:
32
15
23
55
32
14
11

L’istruzione p++ porta p a puntare a vett[1]
(ne contiene l’indirizzo) quindi ora p punta a
vett[1] e p[3] corrisponde a vett[4]
vett:
27
32
p
Equivalenza puntatori e vettori

55
32
11
27
p+3

E’ lecito sottrarre un valore N ad un puntatore
se l’elemento puntato risultante fa ancora parte
del vettore (nell’esempio precedente p-1
punta a vett[0])
15

23
p
p+3
p
punta a (contiene l'indirizzo di) vett
p+3
punta a (produce l'indir. di) vett[3]
*(p+3) equivale a vett[3]

15
Il nome di un vettore può essere utilizzato
come puntatore costante :
*(vett+2) equivale a: vett[2]
vett++
è un errore (vett è costante!)
Il nome di un vettore di T (es. int) che
dovrebbe essere una costante di tipo
puntatore-a-vettore-di-T (o meglio
indirizzo-di-vettore-di-T ), in C “decade” al
tipo puntatore-a-T
Grazie al decadimento vett è visto come
puntatore (costante) a int e punta al suo
primo elemento e vett+1 punta a vett[1]
16
Equivalenza puntatori e vettori


Senza il decadimento, vett+1 punterebbe al
primo byte dopo la fine di vett
Eccezioni:


vett in un sizeof (descritto altrove) non decade
e per questo dà la dimensione dell’intero vettore,
non quella del primo elemento
&vett inibisce il decadimento e produce una
quantità costante di tipo puntatore-a-vettore-di-int
17
Equivalenza puntatori e vettori

Una variabile di tipo puntatore-a-T non “sa”
se il valore (scalare) a cui punta è singolo o è
l’elemento di un vettore, lo sa solo il
programmatore e sta a questi utilizzarlo in
modo coerente
int x = 10, vett[10], *p, *q;
p = &x;
p++; NO! Non esiste l’oggetto puntato da p+1
q = p+1; NO! Idem
p = vett;
p++;
SI’! Ora p punta a vett[1]
q = p+1; SI’! Ora q punta a vett[2]
18
Aritmetica dei puntatori


Attenzione che il puntatore non “sfori” i limiti
del vettore (lo standard non richiede che il
compilatore faccia controlli, molti compilatori
lo offrono opzionalmente, ma ciò riduce le
prestazioni)
E’ lecito che un puntatore punti a quello che
sarebbe l’elemento del vettore successivo
all’ultimo, ma questo puntatore può essere
utilizzato solo per calcolare la differenza tra
puntatori (vedere prossima slide)
19
Aritmetica dei puntatori


Due puntatori a elementi dello stesso vettore
possono essere sottratti, il valore ottenuto +
1 è il numero di elementi del vettore compresi
tra quelli puntati dai due puntatori (inclusi):
p = &vett[4];
q = &vett[10];
d = q-p+1;  7: numero degli elementi
dalla posizione 4 alla
posizione 10 inclusi
Due puntatori possono essere confrontati
solo se fanno parte dello stesso vettore oppure
uno dei due è NULL (o 0)
20
Priorità dell’operatore *


Dalla tabella delle priorità si vede che
l’operatore di deriferimento * ha priorità quasi
massima, inferiore solo alle parentesi (e a ‘->’
e a ‘.’) e associatività da destra a sinistra
Quindi, considerando che gli operatori * e ++
hanno stessa priorità e associatività da D a S:
*p++ equivale a *(p++)  incrementa p
*++p equivale a *(++p)  incrementa p
++*p equivale a ++(*p)  incrementa *p
inoltre:
(*p)++
 incrementa *p
*p+1 equivale a (*p)+1 e non a *(p+1)
Copia di stringhe
21
1a versione



3a versione



La stringa y viene copiata in x
char x[30], y[30], *t=x, *s=y;
gets(y);
while ( (*t = *s) != '\0')
{
t++;
s++;
}
printf("%s\n", x);
Il '\0' viene copiato nel ciclo stesso
Nota: != '\0' può essere omesso
22
2a versione
La stringa y viene copiata in x
char x[30], y[30], *t=x, *s=y;
int i=0;
gets(y);
while (s[i] != '\0')
{
t[i] = s[i];
i++;
}
t[i] = '\0';
printf("%s\n", x);
Il '\0' viene copiato fuori dal ciclo
Qui s e t vengono inutilmente usati come
semplici sinonimi di x e y, non come puntatori
Copia di stringhe
Copia di stringhe
23




La stringa y viene copiata in x
char x[30], y[30], *t=x, *s=y;
int i=0;
gets(y);
while ((t[i] = s[i]) != '\0')
i++;
printf("%s\n", x);
Il '\0' viene copiato nel ciclo stesso
Qui s e t vengono inutilmente usati come
semplici sinonimi di x e y, non come puntatori
Nota: non si può scrivere t[i] = s[i++]
nella condizione del while (side effect)
Copia di stringhe
4a versione



La stringa y viene copiata in x
char x[30], y[30], *t=x, *s=y;
gets(y);
while (*t++ = *s++)
;
printf("%s\n", x);
Il '\0' viene copiato nel ciclo stesso
Nota: l‘istruzione nulla è più chiara se scritta
in una riga a sé stante
24
25
Puntatori e stringhe

Puntatori e stringhe
Si noti la differenza tra le seguenti definizioni:


26


char str[100];
RISERVA spazio per contenere i caratteri, è una
variabile e il suo contenuto può essere modificato
char *s;
NON RISERVA spazio per contenere i caratteri,
quindi per essere utilizzata come stringa le si deve
assegnare una stringa “vera”:

Assegnazione di una stringa variabile:
s = str;
scanf("%s", s);

Si considerino i seguenti esempi:

 SI’
Assegnazione di una stringa costante:
s = "salve";
scanf("%s", s);
 NO
char str[] = "ciao";
E’ l’inizializzazione di una variabile stringa:
il compilatore riserva memoria per str e vi copia i
caratteri di "ciao"; la stringa costante "ciao"
non esiste in memoria: è stata usata dal
compilatore per inizializzare la stringa str, ma
esiste in memoria la stringa variabile "ciao"
str[0]='m';  SI’
char *s = "hello";
E’ l’inizializzazione di una variabile puntatore:
il compilatore determina l’indirizzo della stringa
costante "hello" (che esiste in memoria) e lo
assegna alla variabile puntatore s
s[0]='b';
 NO! "hello" è costante!
27
Puntatori e stringhe

Si considerino i seguenti esempi (cont.):


s = "salve";
E’ l’assegnazione ad una variabile puntatore: il
compilatore determina l’indirizzo della stringa
costante "salve" (che esiste in memoria) e lo
assegna alla variabile puntatore s
s[4]='o';
 NO! "salve" è costante!
s = str;
E’ l’assegnazione ad una variabile puntatore: il
compilatore determina l’indirizzo della stringa
variabile str (che esiste in memoria) e lo assegna
alla variabile puntatore s
s[0]='m';
 SI’
28
Puntatori e stringhe

Noti i puntatori, si possono completare le
informazioni già date sulle funzioni relative
alle stringhe aggiungendo quanto segue:


le funzioni di copia di stringhe strcpy, strncpy,
strcat e strncat restituiscono il puntatore alla
stringa di destinazione
le funzioni di parsing strchr, strrchr, strstr,
strpbrk e strtok restituiscono il puntatore
all’oggetto cercato o NULL se non lo trovano
29
Funzioni sui blocchi di byte




Funzioni sui blocchi di byte
Blocchi di byte: sequenze di byte (caratteri)

qualsiasi, il carattere di codice ASCII 0 ('\0')
è un carattere normale e non viene utilizzato
come terminatore (non c’è alcun terminatore)
Una porzione di memoria (allocata in qualsiasi
modo) viene trattata come generico blocco di
byte da alcune funzioni contenute in
<string.h>
Per riservare una porzione di memoria si può
definire una variabile o una stringa o utilizzare
la funzione malloc (trattata in altre slide)
Nelle seguenti funzioni, s (source) e
t (target ) sono puntatori a blocchi di byte
Puntatori const
31
Puntatore variabile a valore costante

}
30
int const *p;
sono equivalenti
const int *p;
p è una variabile di tipo puntatore-a-costante
(a un oggetto costante di tipo int)
const int x, y;
const int *p;  puntatore-a-costante
p = &x;  SI’, p è una variabile
p = &y;  SI’, p è una variabile
*p = 13;  NO, *p è costante




memcpy(t,s,n)
copia n byte da s a t
memmove(t,s,n)
copia n byte da s a t
(i blocchi possono anche essere sovrapposti)
memcmp(s,t,n)
confronta byte per byte secondo il codice
ASCII i primi n byte di s e di t, il valore
restituito è un int come quello della strcmp
memchr(s,c,n)
cerca il byte c tra i primi n byte di s, dà NULL
se non lo trova o il puntatore ad esso se trova
memset(s,c,n)
copia il byte c in tutti i primi n byte di s
Puntatori const
32
Puntatore variabile a valore costante

L’assegnazione di un valore di tipo puntatorea-costante (l’indirizzo di un valore costante) ad
una variabile di tipo puntatore-a-variabile
genera un Warning del compilatore perché
permette di by-passare la restrizione (const)
const int x = 12;
int y = 10;
int *p;
 puntatore-a-variabile
const int *q;  puntatore-a-costante
p = &x;
 Warning
*p = 5;
 non dà errore
q = &x;
 OK
*p = 5;
 dà errore
Puntatori const
33
Esercizi
Puntatore costante a valore variabile


34
int * const p;
p è una costante di tipo puntatore-a-variabile
(a un oggetto variabile di tipo int)
Le costanti possono essere solo inizializzate
int x, y;
int * const p = &x;  inizializzazione
*p = 13;  SI’, *p è una variabile
p = &y;  NO, p è una costante
1.
2.
3.
4.
Si scriva un programma che chieda una
stringa all’utente e conti quanti siano i
caratteri che la costituiscono, NON si usi la
funzione strlen della libreria standard.
Scrivere un programma che verifichi se la
stringa data in input è palindroma o no
Scrivere un programma che chieda n valori
interi (massimo 100), li collochi in un vettore e
inverta il vettore (scambiando il primo
elemento con l'ultimo, il secondo con il
penultimo, etc.). Si usi la notazione vettoriale.
Come il precedente, ma si usino i puntatori.
35
Esercizi
5.
6.
7.
Scrivere un programma che data una stringa
in input dica se la stessa contiene almeno una
‘A’ tra i primi 10 caratteri.
Si scriva un programma che chieda all’utente
2 stringhe e concateni la seconda alla fine
della prima, NON si usi la funzione strcat
della libreria standard, si usino i puntatori e
non la notazione vettoriale. Attenzione a
terminarla con il carattere ‘\0’.
Si scriva un programma che chieda all’utente
2 stringhe e indichi se la seconda è uguale
alla parte terminale della prima.
36
Esercizi
Scrivere un programma che chieda N valori
(massimo 100), li collochi in un vettore e li
ordini in senso crescente (senza usare vettori
ausiliari).
9. Scrivere un programma che verifichi se la
stringa data è composta di due parti uguali,
trascurando il carattere centrale se la
lunghezza è dispari (es. “CiaoCiao”,
“CiaoXCiao”).
10. Scrivere un programma che date 2 stringhe in
input indichi quante volte la più corta è
contenuta nella più lunga.
8.
37
38
Esercizi
Vettori di puntatori
11. Scrivere

un programma che legga da un file
un testo e spezzi su più righe quelle più
lunghe di N caratteri (N chiesto all’utente). Le
righe si possono spezzare solo dove c’è uno
spazio (che non va riportato nella riga
successiva). L’output deve essere salvato in
un altro file.

Gli elementi di questi vettori sono puntatori
int *vett[10];
definisce un vettore di 10 puntatori a int (le
[ ] hanno priorità maggiore dell’operatore *)
Esempio di inizializzazione
int a, b, c;
int *vett[10]={NULL};
vett[0]=&a;
vett[1]=&b;
vett[2]=&c;
I valori da vett[3] a vett[9] sono tutti
NULL in quanto è stato inizializzato il primo
elemento (i successivi sono automaticamente
a 0 e 0 viene convertito in NULL)
39
Vettori di puntatori

Esempio di inizializzazione errata
int a, b, c;
int *vett[10]={&a, &b, &c};
E’ errato perché questi inizializzatori sono
indirizzi di variabili automatiche (descritto in
altre slide). Se le variabili fossero invece di
classe static sarebbe stato corretto, per
queste variabili i valori di vett si devono
assegnare come visto nell’esempio precedente
40
Puntatori a puntatori


Variabili che contengono l'indirizzo di memoria
di un puntatore
Esempio
int a, *b, **c;
a = 12;
b = &a;
c = &b;
Il puntatore c punta ad una variabile (b) che
punta ad un int (a)
a:B4A
b:A5B
c:5D6
A5B
B4A
12
41
Puntatori a puntatori

42
Puntatori e matrici
Esempio
int a=10, b=20, c=30;
int *v[3], int **w;
v[0]=&a; v[1]=&b; v[2]=&c;
w = v;
w++;
v è un vettore di puntatori, cioè è l'indirizzo di
memoria (“puntatore”) di un puntatore, quindi
v+1 è l'indirizzo del secondo puntatore del
vettore v (ossia è pari a &v[1], punta a b)
Anche w è un puntatore ad un puntatore,
quando viene incrementato, punta al
puntatore successivo, come v



Una matrice è un vettore di vettori e quindi,
considerando che l’associatività di [] è da
sinistra a destra, si ha che:
int Mx[7][5];
definisce un vettore di 7 elementi
ciascuno delle quali è un vettore di 5 int
Gli elementi del vettore Mx sono i 7 vettori
identificati da Mx[i]; quindi Mx[i] è l’indirizzo
di memoria di ciascuno dei 7 vettori di 5 int
Poiché in seguito al decadimento il nome di un
vettore-di-T ha tipo puntatore-a-T, anche gli
Mx[i] non sono di tipo vettore-di-int ma
decadono al tipo puntatore-a-int, (essendo
indirizzi, non si può assegnare loro un valore)
43
Puntatori e matrici





Il “decadimento” del tipo del nome di un
vettore a puntatore può avvenire 1 sola volta
Allora il tipo di una matrice decade a
puntatore-a-vettore-di-T e non a puntatore-aT (quindi incrementando questo puntatore si
punta al vettore di 5 int successivo)
Mx non è di tipo puntatore-a-int come:
int *p
Mx non è di tipo puntatore-a-puntatore-a-int:
int **p
Mx è di tipo puntatore-a-vettore-di-5-int
come: int (*p)[5]
quindi Mx+1 punta al secondo vettore di 5 int
44
Puntatori e matrici


Nella definizione di puntatore seguente
int (*p)[5]
è necessario che la dimensione delle colonne
(5) sia specificata perché definisce un
puntatore-a-vettore-di-cinque-interi
Poiché Mx è un puntatore-a-vettore-di-5-interi
(e non un puntatore ad un intero), allora:
Mx+1 punta all’elemento successivo, ossia al
successivo vettore di 5 interi (la seconda riga
della matrice): Mx+1 aggiunge all’indirizzo di
Mx il numero corretto di byte per puntare al
secondo vettore di 5 int
45
Puntatori e matrici

Puntatori e matrici
Ricapitolando:


46


Mx[1][2]
 è un valore scalare
 è di tipo int
 è modificabile
 Mx[1][2]+1 somma 1 al contenuto di Mx[1][2]
Mx[1]
 è l’indirizzo di un vettore di 5 int
 è di tipo puntatore-a-int (“decade”)


Ricapitolando (continuazione):
Mx


non è modificabile
Mx[1]+1 punta a Mx[1][1]


è l’indirizzo di un vettore di 7 vettori di 5 int
è di tipo puntatore-a-vettore-di-int (“decade
una volta sola”), più precisamente è un
puntatore-a-vettore-di-5-int (senza il 5 nel tipo
il compilatore non saprebbe di quanti byte
spostarsi per puntare al vettore-di-5-int
successivo quando si scrive Mx+1)
non è modificabile
Mx+1 è l’indirizzo di memoria di Mx[1]
47
Puntatori e matrici


Si notino le differenze tra:
int *p;
puntatore-a-int
int (*q)[5]; puntatore-a-vett-di-5-int
Poiché Mx è un puntatore-a-vettore-di-5-int:



p = Mx;
è errata
q = Mx;
è corretta e q+1 è l’indirizzo del secondo vettore di
5 elementi (equivale a Mx[1])
p = &Mx[0][0];
è corretta e p è l’indirizzo del primo elemento dei
Mx[0]
48
Vettori di stringhe

Essendo una stringa un vettore di caratteri,
un vettore di stringhe è in realtà un vettore di
vettori di caratteri, cioè una matrice di char
char str[4][20]={"uno", "due"};
definisce un vettore di 4 stringhe di 20 char
Le 4 stringhe sono identificate da str[i]
str:
str[0] u n o \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
str[1] d u e \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
str[2]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
str[3]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
49
Vettori di puntatori e matrici



Vettori di puntatori e matrici
Si notino le differenze tra:
char a[4][8]={"un","otto","sei"};
char *b[4]={"un","otto","sei"};
a:
b:
un\000000
otto\0000
sei\00000
\00000000
50


un\0
otto\0
NULL
a[2] = "hello";
ERRORE: a[2]non è un puntatore
strcpy(a[2], "hello");
CORRETTO
b[2] = "hello";
CORRETTO: b[2] è una variabile puntatore a cui
viene assegnato l’indirizzo di memoria di una stringa
costante
sei\0
a[i]è l’indirizzo costante della riga i di a, tale
riga è una stringa variabile di 8 char
b[i] è una variabile puntatore con l’indirizzo
della riga i, stringa costante di 4 caratteri: ad
esempio b[2] contiene l’indirizzo di "sei\0"

strcpy(b[2], "hello");
ERRORE: b[2] punta a una stringa costante
Entrambi a[1][0] e b[1][0] sono il carattere 'c'

a[1][0]='m';  SI’! L’oggetto puntato da a[1] è una

b[1][0]='m';  NO! L’oggetto puntato da b[1] è una
stringa variabile
stringa costante
51
52
Const per puntatori a puntatori
Const per puntatori a puntatori
1.
2.
3.
int** x;
x è una variabile di tipo puntatore
a un puntatore variabile
a un oggetto variabile di tipo int
const int** x;
x è una variabile di tipo puntatore
a un puntatore variabile
a un oggetto costante di tipo int
int ** const x;
x è una costante di tipo puntatore
a un puntatore variabile
a un oggetto variabile di tipo int
4.
5.
6.
int * const * x
x è una variabile di tipo puntatore
a un puntatore costante
a un oggetto variabile di tipo int
const int * const * x
x è una variabile di tipo puntatore
a un puntatore costante
a un oggetto costante di tipo int
const int * const * const x
x è una costante di tipo puntatore
a un puntatore costante
a un oggetto costante di tipo int
53
Homework 7
Scrivere un programma che legga da un file al
massimo un certo numero MAXRIGHE di righe di
testo e le memorizzi in una matrice di caratteri
(MAXRIGHE x 100), una riga del file per
ciascuna riga della matrice.
Si definisca un vettore di puntatori a carattere e
lo si inizializzi in modo che il primo puntatore
punti alla prima riga, il secondo alla seconda,
ecc. Si ordinino le stringhe scambiando tra di
loro solo i puntatori e le si visualizzino ordinate.
Facoltativo: misurare il rapporto tra il tempo
necessario per ordinare scambiando le stringhe
e scambiando i puntatori.
54
Homework 7 (esempio)
prima
Nel mezzo del cammin di nostra vita
mi ritrovai per una selva oscura
ché la diritta via era smarrita.
Ahi quanto a dir qual era è cosa dura
esta selva selvaggia e aspra e forte
dopo
Nel mezzo del cammin di nostra vita
mi ritrovai per una selva oscura
ché la diritta via era smarrita.
Ahi quanto a dir qual era è cosa dura
esta selva selvaggia e aspra e forte