PUNTATORI Un puntatore è una variabile destinata a contenere lindirizzo di unaltra variabile...

Preview:

Citation preview

PUNTATORI

• Un puntatore è una variabile destinata a contenere l’indirizzo di un’altra variabile

• Vincolo di tipo: un puntatore a T può contenere solo l’indirizzo di variabili di tipo T.

• Esempio:

int x = 8;int* p;p = &x; /* OK */

PUNTATORI

int x = 8;int* p;p = &x; /* OK */

Da questo momento, *p e x sono due modialternativi per denotare la stessa variabile

xp

8

PUNTATORI

int x = 8;int* p = &x;*p = 31; x--;

Il valore di *p, alias x, è ora 30.

Il valore di p, invece, rimane immutato.

xp

8 30

PUNTATORI

In questo momento, p punta a x, e perciò*p è un alias per x.

Ma un puntatore non è legato per semprealla stessa variabile: può puntare altrove.

int x = 8, y = 66;int *p = &x;(*p)++; /* incrementa x */p = &y; /* ora p punta a y */(*p)--; /* decrementa y */

PUNTATORI

In questo momento, p punta a x, e perciò*p è un alias per x.

Ma un puntatore non è legato per semprealla stessa variabile: può puntare altrove.

int x = 8, y = 66;int *p = &x;(*p)++; /* incrementa x */p = &y; /* ora p punta a y */(*p)--; /* decrementa y */

Le parentesi intorno a (*p)sono necessarie per modi-

ficare l’oggetto puntato da pe non p stesso.

PUNTATORI

• Un puntatore a T può contenere solo l’in-dirizzo di variabili di tipo T: puntatori a tipi diversi sono incompatibili tra loro.

• Esempio:

int x=8,*p; float *q;p = &x; /* OK */q = p; /* NO! */

MOTIVO: il tipo del puntatore serve per dedurre iltipo dell’oggetto puntato, che è una informazioneindispensabile per effettuare il dereferenziamento.

PUNTATORI

Forzare un assegnamento fra puntatori a tipidiversi è possibile mediante un cast esplici-to, ma è molto pericoloso!

int x=8,*p; float *q;q = (float*)&x;

ATTENZIONE!! • È facile scriverlo…• … ma quasi sempre si ottengono solo guai!

Aggirare il type system non è (quasi) mai una buona idea!!

IL SOLITO ESEMPIO

void scambia(int* pa, int* pb) { int t; t = *pa; *pa = *pb; *pb = t;}

main(){ int y = 5, x = 33; int *py = &y, *px = &x; scambia(px, py);} Variazione sul tema: gli indirizzi

di x e y sono posti in due puntatoripx e py prima di passarli.

PUNTATORI

• Un puntatore è una variabile destinata a contenere l’indirizzo di un’altra variabile

• Vincolo di tipo: un puntatore a T può contenere solo l’indirizzo di variabili di tipo T.

• Esempio:

int x = 8;int* p;p = &x; /* OK */

PUNTATORI

int x = 8;int* p;p = &x; /* OK */

Da questo momento, *p e x sono due modialternativi per denotare la stessa variabile

xp

8

PUNTATORI

int x = 8;int* p = &x;*p = 31; x--;

Il valore di *p, alias x, è ora 30.

Il valore di p, invece, rimane immutato.

xp

8 30

PUNTATORI

In questo momento, p punta a x, e perciò*p è un alias per x.

Ma un puntatore non è legato per semprealla stessa variabile: può puntare altrove.

int x = 8, y = 66;int *p = &x;(*p)++; /* incrementa x */p = &y; /* ora p punta a y */(*p)--; /* decrementa y */

PUNTATORI

In questo momento, p punta a x, e perciò*p è un alias per x.

Ma un puntatore non è legato per semprealla stessa variabile: può puntare altrove.

int x = 8, y = 66;int *p = &x;(*p)++; /* incrementa x */p = &y; /* ora p punta a y */(*p)--; /* decrementa y */

Le parentesi intorno a (*p)sono necessarie per modi-

ficare l’oggetto puntato da pe non p stesso.

PUNTATORI

• Un puntatore a T può contenere solo l’in-dirizzo di variabili di tipo T: puntatori a tipi diversi sono incompatibili tra loro.

• Esempio:

int x=8,*p; float *q;p = &x; /* OK */q = p; /* NO! */

MOTIVO: il tipo del puntatore serve per dedurre iltipo dell’oggetto puntato, che è una informazioneindispensabile per effettuare il dereferenziamento.

PUNTATORI

Forzare un assegnamento fra puntatori a tipidiversi è possibile mediante un cast esplici-to, ma è molto pericoloso!

int x=8,*p; float *q;q = (float*)&x;

ATTENZIONE!! • È facile scriverlo…• … ma quasi sempre si ottengono solo guai!

Aggirare il type system non è (quasi) mai una buona idea!!

IL SOLITO ESEMPIO

void scambia(int* pa, int* pb) { int t; t = *pa; *pa = *pb; *pb = t;}

main(){ int y = 5, x = 33; int *py = &y, *px = &x; scambia(px, py);} Variazione sul tema: gli indirizzi

di x e y sono posti in due puntatoripx e py prima di passarli.

IL SOLITO ESEMPIO

Osserva: pa e pb sono copie di px e py!

Il C passa davvero tuttosempre e solo per valore!

RADL

X

Y

PA

PB

33

5

5

33

T 33

RADL

px

py

ESERCIZIO

Scrivere una procedura che, dato un carattere C, lo trasformi in maiuscolo.

Specifica di I° livello:

void maiuscolo(char *pc);restituisce il maiuscolo di C

Specifica di II° livello:

Se *c non è una lettera minuscola, restituiscilo tale e quale. Altrimenti, per calcolare il corrispondente maiu-scolo, sfrutta l’ ordinamento della codifica dei caratteri:– ogni carattere è associato a un intero– le lettere da ‘A’ a ‘Z’ sono in sequenza– le lettere da ‘a’ a ‘z’ sono in sequenza

ESERCIZIO

void maiuscolo(char *pc) {if (*pc<'a' || *pc>'z') return;else *pc –= 'a' - 'A';

}

o anche:

void maiuscolo(char *pc) {if (*pc>='a' && *pc<='z')

*pc += 'A' - 'a';}

Cosa succede se si dimentica un asterisco?

COMUNICAZIONE TRAMITE ENVIRONMENT GLOBALE

Una procedura può anche comunicare conil suo cliente mediante aree dati globali: unesempio sono le variabili globali del C.

Esempio: Divisione intera x/y con calcolo di quoziente eresto.• occorre calcolare due valori• che supponiamo di mettere in due variabili

globali.

COMUNICAZIONE TRAMITE ENVIRONMENT GLOBALE

int quoziente, int resto;

void dividi(int x, int y) { resto = x % y; quoziente = x/y;}

main(){ dividi(33, 6);}

Il risultato è nelle variabili globali quoziente e resto:

il cliente deve andar-selo a prendere!Soprattutto, niente indica

che sia là: bisogna saperlo.

L’ENVIRONMENT GLOBALE

Le variabili globali in C:• sono allocate nell’area dati globale • esistono già prima della chiamata del main• sono inizializzate automaticamente a 0

salvo diversa indicazione (preferibile!!)• possono essere nascoste in una funzione

da una variabile locale omonima• sono visibili, previa dichiarazione extern,

in tutti i file dell’applicazione

L’ENVIRONMENT GLOBALE

Il fatto che le variabili globali in C siano visi-bili, previa dichiarazione extern, in tutti i filedell’applicazione pone dei problemi di prote-zione.

Potrebbe essere utile avere variabili globali• permanenti come tempo di vita• ma protette, nel senso che solo una parte

dell’applicazione possa accedervi.

VARIABILI STATICHE

In C, una variabile può essere dichiaratastatic. In questo modo, essa:• è permanente come tempo di vita• ed è protetta, in quanto è visibile solo

entro il suo scope di definizione.

Nel caso di una variabile globale, ognitentativo di accedervi da altri file, tramitedichiarazioni extern, sarà stroncato dalcompilatore.

ESEMPIO

static int cont = 3;

int nextValue(){return cont++;

}

• La variabile cont è inaccessibile fuori da questo file (il suo scope di definizione); l’unico modo di accedervi è tramite la funzione nextValue

• se un altro file definisse un’altra variabile globale cont, non ci sarebbe comunque collisione, perché la prima esternamente “non esiste”.

VARIABILI STATICHE

Una variabile statica può essere definitaanche dentro a una funzione. Così:• è comunque protetta, in quanto visibile solo

dentro alla funzione (come ogni variabile locale)

• ma è anche permanente, in quanto il suo tempo di vita diventa quello dell’intero programma.

È un mezzo per costruire componenti (fun-zioni) dotati di stato.

ESEMPIO

int nextPrime(void) { static lastprime = 0; if (lastprime>=0 && lastprime<=2)

return ++lastprime; else {

do lastprime += 2;while (!isPrime(lastprime));

return lastprime; }}

Questa funzione restituisce a ogni invocazione il suc-cessivo numero primo.

È un componente dotato di stato: chiamato più volte, dà ogni volta

una risposta diversa

VARIABILI STATICHE

Quindi, la parola chiave static• ha sempre e comunque due effetti

– rende la variabile permanente– rende la variabile protetta

(invisibile fuori dal suo scope di definizione)

• ma se ne vede sempre uno solo per volta– una variabile definita in una funzione, che è

comunque protetta, viene resa permanente– una variabile globale, già di per sé permanente,

viene resa protetta.

COMUNICAZIONE TRAMITE ENVIRONMENT GLOBALE

Una procedura può anche comunicare conil suo cliente mediante aree dati globali: unesempio sono le variabili globali del C.

Esempio: Divisione intera x/y con calcolo di quoziente eresto.• occorre calcolare due valori• che supponiamo di mettere in due variabili

globali.

COMUNICAZIONE TRAMITE ENVIRONMENT GLOBALE

int quoziente, int resto;

void dividi(int x, int y) { resto = x % y; quoziente = x/y;}

main(){ dividi(33, 6);}

Il risultato è nelle variabili globali quoziente e resto:

il cliente deve andar-selo a prendere!Soprattutto, niente indica

che sia là: bisogna saperlo.

L’ENVIRONMENT GLOBALE

Le variabili globali in C:• sono allocate nell’area dati globale • esistono già prima della chiamata del main• sono inizializzate automaticamente a 0

salvo diversa indicazione (preferibile!!)• possono essere nascoste in una funzione

da una variabile locale omonima• sono visibili, previa dichiarazione extern,

in tutti i file dell’applicazione

L’ENVIRONMENT GLOBALE

Il fatto che le variabili globali in C siano visi-bili, previa dichiarazione extern, in tutti i filedell’applicazione pone dei problemi di prote-zione.

Potrebbe essere utile avere variabili globali• permanenti come tempo di vita• ma protette, nel senso che solo una parte

dell’applicazione possa accedervi.

VARIABILI STATICHE

In C, una variabile può essere dichiaratastatic. In questo modo, essa:• è permanente come tempo di vita• ed è protetta, in quanto è visibile solo

entro il suo scope di definizione.

Nel caso di una variabile globale, ognitentativo di accedervi da altri file, tramitedichiarazioni extern, sarà stroncato dalcompilatore.

ESEMPIO

static int cont = 3;

int nextValue(){return cont++;

}

• La variabile cont è inaccessibile fuori da questo file (il suo scope di definizione); l’unico modo di accedervi è tramite la funzione nextValue

• se un altro file definisse un’altra variabile globale cont, non ci sarebbe comunque collisione, perché la prima esternamente “non esiste”.

VARIABILI STATICHE

Una variabile statica può essere definitaanche dentro a una funzione. Così:• è comunque protetta, in quanto visibile solo

dentro alla funzione (come ogni variabile locale)

• ma è anche permanente, in quanto il suo tempo di vita diventa quello dell’intero programma.

È un mezzo per costruire componenti (fun-zioni) dotati di stato.

ESEMPIO

int nextPrime(void) { static lastprime = 0; if (lastprime>=0 && lastprime<=2)

return ++lastprime; else {

do lastprime += 2;while (!isPrime(lastprime));

return lastprime; }}

Questa funzione restituisce a ogni invocazione il suc-cessivo numero primo.

È un componente dotato di stato: chiamato più volte, dà ogni volta

una risposta diversa

VARIABILI STATICHE

Quindi, la parola chiave static• ha sempre e comunque due effetti

– rende la variabile permanente– rende la variabile protetta

(invisibile fuori dal suo scope di definizione)

• ma se ne vede sempre uno solo per volta– una variabile definita in una funzione, che è

comunque protetta, viene resa permanente– una variabile globale, già di per sé permanente,

viene resa protetta.

FUNZIONI STATICHE

Nel secondo significato (protezione enascondimento), la parola chiave static può qualificare anche una funzione.

– rende la funzione protetta(invisibile fuori dal file di definizione)

– può servire per funzioni “a uso interno”, non destinate a essere invocate da altri

static int f(...) {...}

Recommended