1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema...

30
1

Transcript of 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema...

Page 1: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

1

Page 2: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

2

Variabili statiche e dinamiche

Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può essere suddivisa in quattro grandi blocchi:

STACK Stack: zona di memoria che costituisce un’area di appoggio temporaneo

CODICE Codice: contiene il codice macchina del programma

HEAPHeap: zona di memoria libera di essere utilizzata sul momento

DATI Dati: contiene tutte le variabili e le costanti definite nel programma

Page 3: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

3

Il blocco stack è utilizzato principalmente dalle procedure e funzioni

richiamate dal programma; in particolare lo stack conserva le

variabili locali, i valori dei parametri formali passati per valore e gli

indirizzi di quelli passati per riferimento, l’indirizzo di ritorno della

procedura.

Il blocco heap è riservato alle variabili dinamiche.

Lo spazio occupato dai dati e dal codice è fisso.

STACK

CODICE

HEAP

DATI

Page 4: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

4

Allocazione statica.

Memoria viene allocata automaticamente in un processo

mediante una dichiarazione esplicita di un identificatore

che rappresenta una variabile o una costante che

appare nella lista dei parametri di una function.

Tale memoria viene automaticamente deallocata quando

il processo termina.

Page 5: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

5

Allocazione dinamica.

La memoria è allocata e/o deallocata in un processo

mediante delle istruzioni particolari definite in quel

processo. Di norma, tale memoria non è disponibile

prima che l’opportuna istruzione sia posta in essere e

potrebbe continuare o meno ad esistere dopo che il

processo è terminato.

Page 6: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

6

Una variabile allocata dinamicamente è detta variabile

dinamica: per introdurre una tale variabile è necessario

servirsi di un puntatore.

Page 7: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

7

Puntatori

Come è noto in un computer la memoria è organizzata in

celle consecutive, ciascuna della grandezza di un byte.

Queste celle possono essere gestite singolarmente (ad

esempio, per oggetti di tipo char che occupano un 1 byte, o

a gruppi (ad esempio, per oggetti di tipo float che occupano

4 byte, …).

Ad ogni oggetto viene associato un indirizzo di memoria che

rappresenta il primo byte della zona ad esso riservata.

Page 8: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

8

Puntatori

Definiamo puntatore una variabile che contiene l’indirizzo di

un’altra variabile: la variabile p conservata, ad esempio a

partire dall’indirizzo 0x0064fd0, contiene l’indirizzo 0x0064fef

del primo byte della variabile float pi che è un numero reale.

Questa situazione viene descritta scrivendo

float pi=3.1415;

float* p;

p

pi=3.140x0064fef

Page 9: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

9

Puntatori

Per identificare una variabile di tipo puntatore si usa un *

come suffisso al tipo che la variabile rappresenta, come

mostrato di seguito:

float pi=3.1415;

float* p, float* q;

p = π p

pi=3.140x0064fef

L’istruzione float* p associa alla variabile puntatore di nome p un indirizzo a partire dal quale si prevede un’occupazione di memoria necessaria per il tipo float.

Per associare alla variabile p ad esempio il valore contenuto in pi si pone p=&pi. Ovviamente pi deve essere dello stesso tipo di p.

Page 10: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

10

Puntatori

float pi=3.1415; float* p, float* q;p = π

Se ora scriviamoq = p;

Abbiamo che anche la variabile q punta allo stesso indirizzo purchè sia dello stesso tipo di p: l’assegnazione sta ad indicare che l’indirizzo contenuto in p viene copiato in q (che vale ancora 0x0064fef) e che punta, quindi, allo stesso contenuto.

p

pi=3.140x0064fef

q

Page 11: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

11

float n

44.5

…………..  

0x0064fd0  

0x0064fd1  

0x0064fd2  

0x0064fd3  

0x0064fd4  

0x0064fd5  

0x0064fd6  

0x0064fd7  

0x0064fd8  

0x0064fd9  

0x0064fda  

0x0064fdb  

0x0064fdc  

0x0064fdd  

0x0064fde  

0x0064fdf  

0x0064fe0  

0x0064fe1  

0x0064fe2  

0x0064fe3  

0x0064fe4  

………………  

…………..  

Ad esempio se alla variabile float n=44.5 è stata

assegnata la cella 0x0064fd5 (in esadecimale) in

memoria si avrà la situazione mostrata a sinistra.

0x0064fd5

44.5

Page 12: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

12

float n

44.5

…………..  

0x0064fd0  

0x0064fd1  

0x0064fd2  

0x0064fd3  

0x0064fd4  

0x0064fd5  

0x0064fd6  

0x0064fd7  

0x0064fd8  

0x0064fd9  

0x0064fda  

0x0064fdb  

0x0064fdc  

0x0064fdd  

0x0064fde  

0x0064fdf  

0x0064fe0  

0x0064fe1  

0x0064fe2  

0x0064fe3  

0x0064fe4  

………………  

…………..  

Se ora dichiariamo la variabile puntatore

float* pn avremo che in memoria verrà

allocato un byte per pn.

0x0064fd5

44.5

float n=44.5; float* pn;pn= &n;

0x0064fd5 float* pn

0x0064fd5

0x0064fd3

Page 13: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

13

………………………………….0x0064fd0

0x0064fef

………………………………….

4 byte

float* p

p = &pi

pi=3.1415

Ricapitolando definiamo puntatore una variabile che contiene l’indirizzo di un’altra variabile: la variabile p conservata a partire dall’indirizzo 0x0064fd0, contiene l’indirizzo 0x0064fef del primo byte della variabile float pi che è un numero reale.

& è l’operatore di indirizzo

3.1415

0x0064fef

Page 14: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

14

Definite due variabili puntatore p e q ad un float; float* p, float* q;

Supponiamo che esse abbiano come indirizzo (ad es. 0x0064fd0 e 0x0064fd9).Inizialmente il valore di p è nullo.

Posto p = π

alla variabile puntatore p viene associato l’indirizzo della variabile pi ottenendo la situazione vista prima ( l’operatore & è l’operatore di indirizzo );

Posto q = p;

Nell’indirizzo della variabile puntatore q, che deve essere dello stesso tipo di p, viene scritto lo stesso indirizzo contenuto in p (che vale ancora 0x0064fef ) e che punta allo stesso contenuto.

Page 15: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

15

Il simbolo * posto vicino al tipo della variabile è l’operatore di dichiarazione di puntatore;

la scrittura Tipo* p indica che p è una variabile di tipo puntatore che punta a una variabile di tipo Tipo;

poiché il puntatore fornisce l’indirizzo soltanto del primo byte, il sistema conosce esattamente la sua lunghezza soltanto attraverso il tipo.

È assolutamente vietato far puntare un puntatore ad un oggetto che non sia dello stesso tipo di quello proposto nella dichiarazione;

per esempio, tenendo presente le dichiarazioni float* p; int* q il compilatore segnala errore ad una assegnazione del tipo q=p

ATTENZIONE alla istruzione float* p, q; p è un puntatore ad un float mentre q è una variabile float.

Page 16: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

16

Assegnato un puntatore, come si fa ad ottenere l’oggetto da

esso puntato?

Se ap punta ad a, possiamo ottenere il valore di a direttamente

da ap: l’espressione *ap calcola il valore di a.

Tale operatore viene detto operatore di direzione o operatore di

derenferenziazione.

Page 17: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

17

L’istruzione cout<<*p stamperà il contenuto dell’oggetto puntato da p, cioè 3.1415,

Mentre cout<<pstamperà il valore del puntatore p in esadecimale, cioè l’indirizzo a cui punta p (es. 0x0064fef in esadecimale ).Es. il codice che segue produce l’output di figura.

int main() { int a; int *ap; cout<<"a="; cin>>a; ap=&a; cout<<"indirizzo di a = "<<&a<<" valore di a = "<<a<<endl; cout<<"indirizzo di ap = "<<&ap<<" valore di ap = "<<ap<<endl; cout<<" valore a cui punta ap = "<<*ap<<endl; system(“pause”)}

Page 18: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

18

0x22ff74

0x22ff72

0x22ff78

0x22ff73

44

………….

………….

………….

int a; int *ap;cin>>a; ap=&a; cout<<"indirizzo di a = "<<&a<<" valore di a = "<<a<<endl; cout<<"indirizzo di ap = "<<&ap<<" valore di ap = "<<ap<<endl; cout<<" valore a cui punta ap = "<<*ap<<endl;

*ap0x22ff74

0x22ff75

0x22ff76

0x22ff77

&a

a=44

0x22df70&ap

ap

Le operazioni che avvengono in memoria sono illustrate in figura.

Page 19: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

19

E’ possibile assegnare ad un puntatore il valore 0 (o la costante simbolica NULL) in tal caso il puntatore non punta a nulla.

L’indirizzo è di norma composto da tutti zeri e non viene allocata memoria.

int* p=0; // p è un puntatore nullo che non punta a nessun oggetto.

Il puntatore nullo non può essere dereferenziato: i risultati sono imprevedibili ed il programma potrebbe andare in crash.

Page 20: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

20

E’ possibile definire puntatori a vari livelli come mostrato di seguito:

{ int n=44; cout<<" n= "<<n<<endl; cout<<" &n= "<<&n<<endl;int* pn=&n; // pn contiene l'indirizzo di n cout<<" pn= "<<pn<<endl; cout<<" &pn= "<<&pn<<endl; cout<<" *pn= "<<*pn<<endl;int** ppn=&pn ; //ppn contiene l'indirizzo di pn cout<<" ppn= "<<ppn<<endl; cout<<" &ppn= "<<&ppn<<endl; cout<<" *ppn= "<<*ppn<<endl; cout<<" **ppn= "<<**ppn<<endl;}

44

ppn

int**

pn

int*

n

int0x22ff60

0x22ff68

0x22ff64

Page 21: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

21

Un puntatore si dice costante se l’indirizzo non può essere modificato.int n,m,n1=10;int * const p1= &n1 ;p1 = &m ; // l’indirizzo di p1 non può essere modificato: ERRATO

*p1=m; //ma il suo contenuto può essere modificato: CORRETTO

const int* const p2=&n1; // non è possibile modificare né

l’indirizzo di p2 né il suo contenuto

21Allegato puntatori

Page 22: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

22

Puntatori ed array

Quando il compilatore incontra un’espressione tipo a[i] , dove a è un

array di n elementi ed i il suo indice, genera il codice per calcolare

l’indirizzo di a[i] .

Ad esempio, per controllare l’espressione

a[i] < a[i+1]

il compilatore deve prima calcolare gli indirizzi di a[i] e di a[i+1] e poi

eseguire il confronto tra i due valori.

Page 23: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

23

Puntatori ed array

Vediamo il calcolatore come opera.

Innanzitutto l’array deve essere di un Tipo dichiarato (per es. int o double).

Poiché l’array è rappresentato in memoria come una sequenza di byte, il nome a dell’array rappresenta il suo indirizzo-base, cioé l’indirizzo del suo primo elemento, a[0].

Inoltre, tutte le componenti dell’array hanno la stessa lunghezza in byte (che possiamo determinare con sizeof(Tipo)), per cui gli indirizzi dei vari elementi dell’array possono essere calcolati come

a + i x sizeof(Tipo) per i=0, 1, 2 ………., n

Page 24: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

24

Il compilatore sostituisce ogni riferimento ad a[i] con il calcolo precedente eseguendo le operazioni di addizione e moltiplicazione.

Una maniera più efficiente di operare è quello di inizializzare una variabile puntatore all’indirizzo-base dell’array e poi aggiungere la quantità sizeof(Tipo) ad ogni passo del ciclo.

Ciò può essere ottenuto in maniera semplice scrivendo

*(a + i)

il compilatore:1. determina l’indirizzo del primo elemento dell’array a;2. aggiunge i volte la grandezza del Tipo dell’elemento;3. restituisce l’indirizzo totale.

Page 25: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

25

int main(){ const int Size=3; short a[Size]={22,33,44}; cout<<“a “<<a<<endl; cout<<“size of short “<<sizeof(short)<<endl; short* end=a+Size; short sum=0; for (short* p=a;p<end;p++)

{sum+=*p;cout<<“\t p= “<<p;cout<<“\t *p= “<<*p;cout<<“\t sum= “<<sum<<endl;}

}

Allegato scorrArrayPuntatori

Il codice mostrato a destra e l’output sottostante mostrano gli indirizzi e il contenuto dell’array sommato passo passo.

Page 26: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

26

A titolo esemplificativo riscriviamo le function inserite nel

file InsertArray.h.

Ricordiamo che la chiamata del vettore deve essere fatta

con un puntatore.

Allegato InsertArray.h

Page 27: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

27

void LeggeVettore(int [],const int,char, int=100,bool=true);

void StampaVettore (const int [],const int, char);

void LeggeVettore (int vet[],const int n, char nome, int nr, bool Acaso)

{ int i; if (Acaso){ srand(time(0)); for (i=0; i<n; i++) { vet[i]=rand() % nr - nr/2; cout<<nome<<"["<<i<<"]="<<vet[i]<<" "; } cout<<endl;} else { for (i=0; i<n; i++) { cout<<nome<<"["<<i<<"]="; cin>>vet[i]; } } }void StampaVettore (const int vet[], const

int n, char nome) { int i; cout<<nome<<"={"; for (i=0; i<n; i++) if (i<n-1) cout<<vet[i]<<","; else cout<<vet[i]<<"}"<<endl; }

È necessario introdurre il simbolo di puntatore in entrambi i casi evidenziati:

int * in luogo di int [ ]

L’istruzione in grassetto va sostituita con

*(vet+i)=rand() % nr - nr/2;

che risulterà essere più veloce.

In generale, ogni occorrenza divet[i]

deve essere sostituita con*(vet+i)

Page 28: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

28

void LeggeVettore(int*,const int, char, int=100, bool=true);

void StampaVettore (const int*,const int, char);

void LeggeVettore(int *vet,const int n, char nome,int nr,bool Acaso)

{ int i; if (Acaso){ srand(time(0)); for (i=0; i<n; i++) { *vet[i+]=rand() % nr - nr/2; cout<<nome<<"["<<i<<"]="<<vet[i]<<" "; } cout<<endl;} else { for (i=0; i<n; i++) { cout<<nome<<"["<<i<<"]="; cin>>*vet[i+]; } } }void StampaVettore(const int *vet, const int n, char nome) { int i; cout<<nome<<"={"; for (i=0; i<n; i++) if (i<n-1) cout<<*vet[i+]<<","; else cout<<*vet[i+]<<"}"<<endl; }

Il codice riscritto è illustrato a destra.

Allegato InsertArrayPunt.h

void LeggeVettore(int [],const int,char, int=100,bool=true);

void StampaVettore (const int [],const int, char);

void LeggeVettore (int vet[],const int n, char nome, int nr, bool Acaso)

{ int i; if (Acaso){ srand(time(0)); for (i=0; i<n; i++) { vet[i]=rand() % nr - nr/2; cout<<nome<<"["<<i<<"]="<<vet[i]<<" "; } cout<<endl;} else { for (i=0; i<n; i++) { cout<<nome<<"["<<i<<"]="; cin>>vet[i]; } } }void StampaVettore (const int vet[], const

int n, char nome) { int i; cout<<nome<<"={"; for (i=0; i<n; i++) if (i<n-1) cout<<vet[i]<<","; else cout<<vet[i]<<"}"<<endl; }

Page 29: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

29

Allegato InsertArrayPunt.h

// Selection sort con puntatori sortPuntatori2

Esercizio

Scrivere una procedura ricorsiva che su un array ordinato ricercaUn determinato valore utilizzando la ricerca binaria utilizzando i puntatori.

Esercizio

Scrivere una procedura ricorsiva che ordini con l’inserction sort un arrayassegnato da tastiera utilizzando i puntatori.

Page 30: 1. 2 Variabili statiche e dinamiche Un programma è un processo in esecuzione a cui il sistema operativo assegna una certa zona di memoria. Tale zona può.

Se si vuole che la cella puntata non possa essere modificata, allora è utile introdurre la clausola const davanti alla definizione ottenendo il puntatore a costante.…………….int n=3;const int* p1; // p1 punta ad un intero costante p1=&n; // viene segnalato un errore perché

la cella n non può essere modificata

Dall’esempio si trae inoltre che un oggetto dichiarato costante può essere puntato soltanto da un puntatore costante.