corso di fondamenti di informatica - unina stidueunina.stidue.net/fondamenti di...

28
Corso di Fondamenti di Informatica Puntatori e Allocazione Dinamica

Upload: others

Post on 25-Aug-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Corso di Fondamenti di Informatica

Puntatori e Allocazione Dinamica

Page 2: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori (Richiamo)   Il C++ prevede puntatori a dati – di qualsiasi natura,

semplici o strutturati – e puntatori a funzione. In particolare il puntatore viene utilizzato:

  per il riferimento a variabili dinamiche;   per il riferimento a funzioni;   per gli array,

  in particolare per l'elaborazione di stringhe;   per i parametri formali di funzione,

  in alternativa allo scambio per riferimento;   per il riferimento a locazioni specifiche della memoria,

associate a dispositivi hardware   ad esempio per l’ingresso-uscita

Page 3: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori: notazioni in C++ (Richiamo)

•  p è un variabile di tipo puntatore •  p=&x al puntatore p viene assegnato l’indirizzo di x •  *p denota la variabile puntata da p

&p=

&x=

Esempio: Sia x una variabile di indirizzo 127 e valore 0,3; p è un puntatore ad x;

Page 4: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori: operazioni (Richiamo) •  char* pc; //pc è un puntatore a variabile di tipo carattere •  int* pi; //pi è un puntatore a variabile di tipo intero •  float* pf; //pf è un puntatore a variabile di tipo float

•  double* pd; //pd è un puntatore a variabile di tipo doppia

precisione C++ tratta esplicitamente le espressioni di tipo puntatore. In particolare sono previsti i seguenti operatori:

•  l’operatore di assegnazione tra puntatori che puntano allo stesso tipo T*; •  gli operatori unari di incremento ++ e decremento -- unitari (in forma prefissa e postfissa ++p, p++, --p, p--); •  l'operatore di somma o differenza tra un puntatore ed un intero (p+i punta all'elemento che segue di i posizioni quello puntato da p);

Page 5: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori: operazioni

T * p;

p=p+1; p=p+sizeof(T);

  L’incremento a p è tale che p+1 punta all’area di memoria immediatamente successiva a quella impegnata dall’elemento puntato da p.

  sizeof(T) è un operatore che applicato al nome di un tipo restituisce il numero di byte necessario alla rappresentazione in memoria di una variabile di quel tipo

  Questa tecnica è particolarmente utile per i puntatori ad array

Page 6: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori a dati strutturati

Un puntatore può puntare a variabili strutturate (di tipo array o record). Esamineremo i seguenti casi:

•  puntatore ad array;

•  puntatore a record;

Tra i casi elencati, il puntatore ad array può utilmente essere sostituito dalla notazione a[i] tipica degli array

Page 7: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori ad array Un puntatore ad un array a è una variabile che punta alla prima locazione dell'array (a[0] in C++);

considerando che i successivi elementi dell'array sono allocati in posizioni contigue, esso consente di puntare anche a tutti gli altri elementi dell'array.

T a[dim]; // a è un array di dim elementi di tipo T T* p ; // p è un puntatore a T

p=a; p=&a[0];

Un puntatore ad array è dunque di per sé un puntatore al tipo T degli elementi dell'array

Page 8: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

I puntatori ad array: esempio

const int dim=100; float a[dim]; // a è un array di dim elementi di tipo float float* p ; // p è un puntatore a float

//azzeramento di tutti gli elementi di un array di 100 elementi for (float* p = a, int i=0; i<dim; i++, p++)

*p= 0;

Page 9: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Stringhe e Puntatori

  Una costante stringa viene memorizzata come array di caratteri con l'aggiunta di un carattere nullo alla fine della stringa.

  Poiché un puntatore a char può contenere l'indirizzo di un char, è possibile definire: –  char* stringa = "Hello World";

  Che equivale a:

–  char* stringa; –  stringa = "Hello Word";

Page 10: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Esempio strlen (ver. 1)

int strlen(char *s) { char* start = s; while (*s++); return s-start; }

Page 11: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

strcmp (ver. 1)

int strcmp(unsigned char *s1,unsigned char *s2) { while (*s1 && *s2 && *s1 == *s2) s1++, s2++; return (*s1 - *s2); }

Distanza tra stringhe

Page 12: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Strcpy (vers. 1)

void strcpy(char *dest,char *src) { while (*dest++ = *src++) ; }

Page 13: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Puntatori a record Un puntatore ad un record è una variabile che punta all'indirizzo di memoria ove il record è allocato; esso è molto utile nella realizzazione dei tipi dinamici

// Dichiarazioni di un tipo strutturato Ts struct Ts { // Ts è un tipo strutturato

D1; .....; Dn ; };

Ts r ; // r è variabile di tipo Ts

La funzione di accesso al singolo campo del record è l’operatore punto (.). Per accedere al campo D1 della variabile r la sintassi è: r.D1

// Dichiarazione di variabile di tipo puntatore a Ts Ts* p;

Page 14: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Puntatori a record Ts* p = &r; // p è una variabile puntatore inizializzata ad r

p può essere ridefinito nel corso del programma

p= &r1; //ora p punta alla variabile r1 di tipo Ts

(*p).Di; p->Di;

Accesso alla singola componente di un record attraverso il puntatore a record:

Page 15: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Puntatori a record: un esempio // Definizione di tipo struttura: struct Abbonati { // definisce struttura di nome Abbonati

char[10] nominativo; char[10] indirizzo; int numTel ; };

// Definizione di variabili Abbonati a; // a una variabile di tipo Abbonati Abbonati * p= &a; // p puntatore al tipo Abbonati, è

// inizializzato con l’indirizzo di a

// Accesso alla componente nominativo mediante puntatore p->nominativo;

Page 16: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Variabili e strutture dinamiche La gestione delle variabili dinamiche è resa possibile dalla disponibilità dei seguenti meccanismi linguistici:

  variabili di tipo puntatore;

 operatore new

 operatore delete

Page 17: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Operatore new

In fase di esecuzione, new alloca un'area di memoria sufficiente ad ospitare un valore del tipo T e restituisce il puntatore a tale area;

il tipo T definisce implicitamente l'ampiezza dell'area di memoria occorrente.

Nel caso in cui l’allocazione dell’area richiesta non sia possibile, l’operatore new restituisce il valore NULL

T* p = new T; //alloca memoria sufficiente a contenere un // oggetto di tipo T e restituisce puntatore

T* p1 =new T[n]; //alloca memoria sufficiente a contenere n // elementi di tipo T e restituisce puntatore

Page 18: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Operatore delete

Produce la deallocazione dell'area di memoria puntata dalla variabile p, cioè annulla l'allocazione, rendendo nuovamente disponibile lo spazio di memoria prima occupato.

delete p; //dealloca area puntata da p

delete [] p1; //dealloca tutto l'array precedentemente allocato

Page 19: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Allocazione della memoria

Area progr.

Area dati statici

Area heap

Area stack

void main() {

}

int *p;

10

10 20

p=new int;

*p=20;

delete p;

Page 20: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Area codice

Area dati statici

Area heap

Area stack

100

100 34

p

Allocazione delle variabili dinamiche

void main() {

}

int *p; //var. autom.

p=new int;

*p=34;

delete p;

Il puntatore p è una variabile automatica, quindi allocata in area stack. Dopo l’istruzione new, p punta ad una locazione nello heap atta a contenere un intero

Esempio

Page 21: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Allocazione dinamica di un vettore Con l’allocazione dinamica di un vettore il puntatore restituito è quello all'indirizzo del primo elemento del vettore, pertanto è di tipo T* se T è il tipo degli elementi del vettore

float* a= new float[n];

Il riferimento agli elementi del vettore viene espresso a mezzo della consueta notazione con indice

a[i] = 10.0 *(a+i)=10.0

delete [] a; //cancella l'intero vettore precedentemente allocato

Page 22: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Esempio: // allocazione del vettore con deallocazione ed esempio di leak memory

#include <iostream> #include <math.h> #include <stdlib.h> using namespace std;

int main(void) {

int *vett; int n = 1000000;

while (true) { vett = new int[n]; cout << "allocati " << n*sizeof(int) << " byte" << endl;

delete [] vett; cout << "deallocati " << n*sizeof(int) << " byte" << endl; } return 0; }

Page 23: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Allocazione dinamica di una stringa   Con l’allocazione dinamica di una stringa il puntatore

restituito è quello all’indirizzo del primo elemento della stringa. Pertanto è di tipo char *

  L’istruzione precedente alloca spazio per una stringa di n caratteri più il terminatore

  Valgono le stesse considerazioni fatte per i vettori

char* s= new char[n+1];

Page 24: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Esempio: #include <iostream> #include <stdlib.h>

using namespace std;

int main(int argc, char *argv[]) { char * stringa; int n;

cout << "\n quanto e' lunga la stringa che vuoi inserire?"; cin >> n;

stringa = new char[n+1];

cout << "\n inserisci la stringa: "; cin.ignore();

cin.getline(stringa,n+1); //inserisce il terminatore

cout << "\n hai inserito: "; cout << stringa; system("PAUSE"); return 0; }

Page 25: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Allocazione dinamica di un record

L'allocazione dinamica di un record avviene analogamente attraverso l'uso dell'operatore new

Indicato con R un tipo record e con r un puntatore ad R, si ha:

R* r = new R;

Page 26: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Esempio: #include <iostream> #include <math.h> #include <stdlib.h> using namespace std;

struct Punto { float X; float Y; };

int main(void) {

Punto P1; // allocazione statica P1.X=0.0; P1.Y=0.0;

Punto * PuntP; PuntP=new Punto; PuntP->X=3; // (*PuntP).X PuntP->Y=4; // (*PuntP).Y

cout << "\n le coordinate del punto P1: " << P1.X << "," << P1.Y; cout << "\n le coordinate del punto allocato dinamicamente: " << PuntP->X << "," << PuntP->Y;

system("PAUSE"); return 0; }

Page 27: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Errori comuni con puntatori e variabili dinamiche

  Tipici errori quando si usa l’allocazione dinamica sono:

–  Dimenticare di allocare un dato nello heap e usare il puntatore come se lo stesse riferendo (produce un effetto impredicibile)

–  Dimenticare di “restituire” la memoria allocata quando non serve più (rischio di memory leak)

–  Tentare di usare dati dinamici dopo che sono stati deallocati

–  Invocare delete più di una volta sullo stesso dato

Page 28: Corso di Fondamenti di Informatica - UniNa STiDuEunina.stidue.net/Fondamenti di Informatica/Materiale/1. C...Errori comuni con puntatori e variabili dinamiche Tipici errori quando

Riferimenti   Da C++ a UML

– Capitolo 8; §1,§2, §8.3.1 (Richiamo) – Capitolo 8; §8.3.5, §8.4

  Da Fondamenti di Informatica II – Parte II, Capitolo VII, §6 (Richiamo) – Parte II, Capitolo VIII, §2 (Richiamo)