Sono variabili il cui valore corrisponde ad un indirizzo di memoria
Puntatori
Dichiarazione di variabile puntatore
• Esistono puntatori per ogni tipo di variabile puntata
– Un dato puntatore può puntare solo a un determinato tipo di variabili, quello specificato nella dichiarazione
• Si usa il qualificatore di tipo (suffisso) *
– Es. : int* pointer; (ma anche int *pointer)
– dichiara la variabile pointer, puntatore ad una qualunque variabile di tipo int
Operatore di indirizzo &
• L’operatore unario di indirizzo & restituisce l’indirizzo della locazione di memoria dell’operando
– Il valore restituito non va usato come l-value
– (in quanto l’indirizzo di memoria di una variabile non può essere assegnato in un’istruzione, ma è predeterminato)
Operatore di indirizzo &
Es.:
&a ammesso
&(a+1) non ammesso
&a = b non ammesso
Perché? (in quanto l’indirizzo di memoria di una variabile non
può essere modificato in un’istruzione, ma solo usato come
riferimento in quanto è predeterminato e non modificabile)
Assegnazione di valore a un puntatore
NON si possono assegnare valori a un puntatore, salvo che in questi tre casi:
1. a un puntatore é assegnato il valore NULL (non punta a
“niente”)
2. a un puntatore è assegnato l’indirizzo di una variabile esistente, restituito dall’operatore &
( Es. int a; int* p; p=&a; )
3. é eseguita un’operazione di allocazione dinamica della
memoria
L’operatore di dereferenziazione *
Consideriamo int y=5;
int *yPtr;
yPtr = &y;
Operazioni sui puntatori
Operazioni fondamentali:
Assegnazione di valore (indirizzo) ad un puntatore int* pi = &i p = q
Riferimento all’oggetto puntato *pi=3
Confronto tra puntatori (==, !=)
Operazioni sui puntatori
E’ possibile specificare che un dato puntatore non deve essere usato per modificare l’oggetto puntato attraverso la parola chiave const:
int i;
const int* p=&i;
Le istruzioni in cui si usa p per aggiornare i vengono segnalate
come erronee
L’operatore di dereferenziazione *
L’operatore unario di dereferenziazione * di un puntatore restituisce il valore della variabile puntata dall’operando:
come r-value, esegue un’operazione di estrazione
Es.: a = *p; assegna ad a il valore della variabile puntata da p come l-value, esegue un’operazione di inserimento
Es.: *p = a; assegna il valore di a alla variabile puntata da p
L’operatore di dereferenziazione *
l’operazione di deref. é inversa a quella di indirizzo.
Se assegniamo a un puntatore p l’indirizzo di una variabile a,
p = &a;
allora
*p == a
cioè la deref. di p coincide con a
L’operatore di dereferenziazione *
ATTENZIONE: non é detto il contrario !!!
se si assegna alla deref. di p il valore di a,
*p = a ;
ciò non comporta automaticamente che in p si ritrovi l’indirizzo
di a, ma semplicemente che il valore della variabile puntata da p
coinciderà con a
Attenzione!
la dichiarazione di un puntatore comporta allocazione di memoria per la variabile puntatore, ma non per la variabile puntata.
Es.: int* lista;
alloca memoria per lista ma non per la variabile puntata da
lista
Array e puntatori
Il nome di un array è in realtà un puntatore costante all’indirizzo di partenza dell’array stesso, per cui non può essere modificato nelle operazioni di aritmetica dei puntatori.
I puntatori possono essere utilizzati in tutte le
operazioni di indicizzazione di un array
Array e puntatori
La dichiarazione di un array comporta allocazione di memoria di una variabile puntatore (il nome dell’array), e dell’area puntata, di lunghezza predefinita
il puntatore é dichiarato const e inizializzato con l’indirizzo dell’area puntata (cioè del primo elemento dell’array)
Es.: int lista[5];
• alloca memoria per il puntatore costante lista;
• alloca memoria per 5 valori di tipo int;
• inizializza lista con &lista[0]
Array e puntatori (1)
Il nome (usato da solo) di un array ha il significato di puntatore al primo elemento dell’array
Ogni altro elemento é accessibile tramite la deref. del puntatore-array incrementato di una quantità pari all’indice/offset dell’elemento ovvero le espressioni (dato un array A):
A[i] e *(A+i)
conducono ad identico risultato anche se sono due formalismi
diversi.
Array e puntatori (2)
Se A[N] è un array di indirizzo ind,
A[i] il suo elemento i-esimo (i intero),
l’indirizzo di A[i] sarà dato dall’espressione
*(ind+i)
C funzioni
àargomenti
passaggio dei parametri per riferimento (per indirizzo): come parametro della funzione viene passato l’indirizzo di una variabile
• L’argomento deve essere di tipo puntatore al tipo del dato su cui si opera
• L’argomento (il suo nome) si comporta come un sinonimo (alias) del corrispondente parametro passato
Record di attivazione a
b
Indirizzo di rientro in foo
...r automatiche
Indirizzo di rientro in main
...k
automatiche
a2
a1 28
12
argomenti
void foo(...) {
...k = mcd(&a1,&a2) } ...
funzione chiamante
int mcd(int *a, int *b){
int r;
} ...
funzione chiamata
main {
Stringhe
In memoria le stringhe sono degli array di tipo char, con una particolarità in più, che le fa riconoscere da operatori e funzioni come stringhe e non come normali array:
l’elemento dell’array che segue l’ultimo carattere della stringa
deve contenere il carattere NULL o ‘\0’ (detto in questo caso
terminatore); si dice pertanto che una stringa é un “array di
tipo char null terminated“.
Inizializzazione di variabili stringa
Se nella dichiarazione-inizializzazione si omette la dimensione dell’array, questa viene automaticamente definita dalla lunghezza della costante stringa aumentata di uno, per far posto al terminatore (in questo caso la stringa non può più essere “allungata”!):
char Saluto[] = “Ciao”;
allocato in memoria array con 5 elementi
Dichiarazione di stringhe
Es.:
char MiaVar[30];Dichiara la variabile MiaVar come array di tipo char con massimo 30 elementi. Affinché MiaVar sia identificata (in lettura) da operatori e funzioni come stringa, dobbiamo inserire nell’array una serie di caratteri terminati da un NULL.
Se vogliamo che MiaVar presenti a operatori e funzioni la stringa
“Ciao”, dobbiamo scrivere invece le istruzioni:
MiaVar[0]=’C’; MiaVar[1]=’i’;
MiaVar[2]=’a’; MiaVar[3]=’o’;
MiaVar[4]=’\0’;
impegnando così 5 elementi dell’array dei 30 disponibili (i
rimanenti 25 saranno ignorati).
Considerazioni
ATTENZIONE:
In caso che si creino delle stringhe con un numero di caratteri
(compreso il terminatore) maggiore di quello dichiarato, il
programma non produce direttamente messaggi di errore, ma
invade zone di memoria non di sua pertinenza, con
conseguenze imprevedibili (spesso si verifica un errore fatale
a livello di sistema operativo).
C libreria string.h
La libreria string (string.h) contiene funzioni di manipolazione di stringhe
Prototipo Descrizione
char *strcpy(char *s, char *cs); copia cs in s e ritorna s char *strcat(char *s, char *cs); concatena cs ad s e ritorna s
int strcmp(char *cs1, char *cs2); confronta cs1 e cs2; se cs1 < cs2 il valore di ritorno è < 0; se cs1 > cs2 il valore di ritorno è > 0;
se le due stringhe sono uguali il valore di ritorno è 0 char *strstr(char *cs1, char *cs2); restituisce un puntatore alla prima occorrenza in
cs1 della stringa cs2
size_t strlen(char *cs); restituisce la lunghezza di cs
... …
Array di puntatori
I puntatori, come qualsiasi altra variabile, possono essere raggruppati in array e dichiarati come:
Es.: int* A[10] ;
dichiara un array di 10 puntatori a int
Come il nome di un array equivale a un puntatore, così un
array di puntatori equivale a un puntatore a puntatore (con in
più l’allocazione della memoria puntata, come nel caso di
array generico)
Array di Stringhe
Il caso più frequente di array di puntatori é quello dell’array di stringhe, che consente anche l’inizializzazione (atipicamente) delle stringhe che costituiscono l’array
Es.: char* colori[3] = {‘’Blu’’, ‘’Rosso’’, ‘’Verde’’} ;
Le stringhe possono essere di differente lunghezza; in
memoria sono allocate consecutivamente e, sono riservati
tanti bytes quant’è la rispettiva lunghezza (terminatore
compreso).
Array di puntatori
suit[4] indica un array di 4 elementi
char* suit[4] = {“Heart”, “Diamond”,
“Clubs”, “Spades”}
Ogni elemento dell’array è un puntatore ad un char, l’array contiene in realtà soltanto i puntatori al primo carattere di ogni stringa. Pur avendo l’array suit
dimensione fissa, si può accedere a stringhe di qualsiasi
lunghezza.
C libreria utilità stringhe
Problema: Data una stringa qualsiasi verificare se è palindroma
Una stringa è palindroma quando ha uguali i caratteri che hanno la stessa distanza dal centro della stringa. Per esempio
Palindromi NON palindromi
ANNA AMARA
ADA AROMA
DEOED ODE
baccdccab abcab
detta n la lunghezza della stringa, se è palindroma sarà:
s[i]=s[n-1-i] per ogni i=0,…,n-1
Esercizi su funzioni e array
Esercizi: usare le funzioni di utilità per vettori e per stringhe
1. Generato in modo random un vettore contenente N interi relativi compresi tra –M ed M mediante una procedura, risolvere i seguenti problemi :
scrivere un programma che stampi tutti i numeri positivi e la loro posizione scrivere un programma che stampi tutti i numeri minori o uguali a zero scrivere un programma che stampi il più grande ed il più piccolo e le loro
posizioni
scrivere un programma che stampi tutti i numeri maggiori di un valore dato e le posizioni
scrivere una procedura che restituisca tutte le posizioni dei numeri negativi 2. Definire una funzione Uguali2 che prenda in input un vettore V di interi di
lunghezza n, e restituisca:
true se il vettore contiene almeno due numeri uguali, false altrimenti Esempi: Se V=[1,22,13,24,5] allora Uguali2(V) à false
Se invece V=[1,2,6,24,2] è Uguali2(V) à true
Esercizi su funzioni e array
3. Definire una procedura PrecSegueX che abbia in input un vettore V di interi di lunghezza n, ed un numero X, e:
inserisca all’inizio di V i valori di V minori o uguali ad X (preservandone l’ordine);
inserisca in seguito tutti i valori di V maggiori di X (preservandone l’ordine).
Esempio: Sia V= [56,35,4,2,22]. L’output di PrecSegueX(V,40) deve essere: V=[35,4,2,22,56]
4. Definire una funzione ContaCifre che prenda in input un vettore V di interi di lunghezza n, ed un numero X e conti quante volte tutte le cifre di X siano contenute negli elementi che compongono il vettore
Esempio: Siano V=[484,325,12,8489,48,12487,1284] e X=48;
ContaCifre(V,7,48) à 4
(sono evidenziati i numeri che contengono al loro “interno” il numero 48).
5. Definire una procedura GoDestra, che, assegnato un vettore V di n elementi ed un intero m, 0£ m £ n, sposti verso destra di m passi tutti gli elementi del vettore V
Esempio: Sia V=[7,8,9,0] ed n=4 otteniamo GoDestra(V,3) fa diventare V=[8,9,0,7]
Esercizi su funzioni e array
6. Scrivere una procedura Comuni, che assegnati due vettori V1, V2 di
dimensioni rispettivamente n1 ed n2, ponga in un altro vettore V3 tutti e soli gli elementi di V1 che compaiono anche in V2, conservando l’ordine con cui compaiono in V1
Esempio: Siano V1=[1,2,3,4,5], V2=[5,0,3,0,1], V3 qualunque.
Eseguiamo Comuni(V1, V2,V3). Allora V3 diventa [1,3,5]
7. Definire una procedura PariDispari che dato un vettore V di interi di lunghezza n:
ponga all’inizio di V i valori di V pari, nello stesso ordine in cui si trovavano in V;
li faccia seguire dai valori di V dispari, di nuovo nello stesso ordine in cui si trovano in V.
Esempio: Sia V= [5,3,4,2,1]. Eseguiamo PariDispari si deve avere: V = [4,2,5,3,1]
8. Scrivere una funzione che dato un array V di interi di dimensione n
restituisce true se nell’array V c’è un valore che è uguale alla somma di tutti i valori che lo precedono, false altrimenti
Esempio. V=[1, 4, 4, 9, 3] la funzione restituisce true perché V[3]=9=1+4+4
V=[1,3,5,8,3] la funzione restituisce false
Esercizi su funzioni e array
9. Scrivere una procedura che dati 2 array di interi V1 e V2 di dimensione n restituisce nell’array V3 gli elementi che appartengono a V1 ma non a V2 non ripetuti e in N3 il numero di tali elementi
Esempio: V1= [2, 4, 4, 5, 3] e V2= [7, 3 ,10 ,6 ,7] si deve ottenere V3= [ 2, 4, 5] con N3 =3
10. Scrivere una funzione che data una stringa s ed un carattere car restituisce il numero massimo di caratteri car consecutivi presenti nell’array
Esempio: s = ‘abcaacaaabaa', car=’a’ la funzione deve restituire 3 11. Scrivere una procedura che dato un array a ordinato di dimensione N
inserisce nell’array il valore x in modo tale che l’array dopo l’inserimento sia ancora ordinato
Esempio: Siano a = [2, 3, 7, 11, 24] e x =5 si deve ottenere a = [2, 3, 5, 7, 11,24 ]
Esercizi su funzioni e array
12. Scrivere un programma che, dati due vettori di interi di dimensione N, ne costruisca un terzo di dimensione 2N i cui elementi di posizione pari siano gli elementi del primo vettore e gli elementi di posizione dispari siano gli
elementi del secondo vettore. Strutturare il programma in procedure e funzioni
13. Scrivere un programma che, dato un vettore V1 di reali di dimensione N, ne generi un altro V2 così definito: il primo elemento di V2 è dato dal prodotto degli elementi 1 e 2 di V1, il secondo elemento di V2 è dato dal prodotto degli elementi 3 e 4 di V1, e così via
Esercizi su funzioni e array
14.Scrivere una procedura che genera un vettore V di numeri reali di dimensioni N (N£100). Con tale procedura scrivere un programma che
stampi prima tutti gli elementi di posto dispari e poi quelli di posto pari,
letto un indice h stampi l’indice ed il valore del più piccolo fra i numeri maggiori di V[h];
stampi l’indice ed il valore dei numeri di valore dispari massimo e minimo;
si costruisca e quindi si stampi un secondo array di N elementi tali che il primo
elemento contenga la somma di tutti gli N numeri, il secondo la somma dei numeri dal secondo in poi, il terzo la somma dal terzo in poi e così via;
si stampi l’indice ed il valore dell’elemento massimo fra gli elementi di posto dispari, quindi l’indice ed il valore del minimo fra gli elementi di posto pari;
letto un indice h, si costruisca e quindi si stampi un array di N elementi tali che il
primo sia quello specificato dall’indice, il secondo sia quello precedente e così fino al primo, poi proseguendo dall’ultimo retrocedendo fino a completare l’array.
15.Scrivere un programma che prenda in input un vettore già ordinato di interi e stampi in output l’istogramma delle occorrenze di ogni elemento del vettore.
Esempio. dato il vettore V=[1,1,1,3,5,5,7,7,7,7,10,10], deve stampare:
1 ***
3 *5 **
7 ****
10 **