Passaggio parametri puntatore - Dipartimento di Ingegneria ...bloisi/didattica/ingegneria... ·...

Post on 25-Aug-2020

2 views 0 download

Transcript of Passaggio parametri puntatore - Dipartimento di Ingegneria ...bloisi/didattica/ingegneria... ·...

Corso di Laboratorio di Informatica

Ingegneria Clinica – BCLR

Unità 6

Passaggio parametri

puntatore

Domenico Daniele Bloisi

Docente

Ing. Domenico Daniele Bloisi, PhD

Ricercatore

Dipartimento di Ingegneria Informatica, Automatica

e Gestionale “Antonio Ruberti”

Via Ariosto 25

(adiacente Piazza Dante,

Manzoni

Tram 3 fermata via Labicana)

email: bloisi@dis.uniroma1.it

home page:

Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Pagina 2

http://www.dis.uniroma1.it/~bloisi

Ricevimento

In aula, subito dopo le lezioni

Su appuntamento (tramite invio di una email)

presso:

Dipartimento di Ingegneria Informatica,

Automatica e Gestionale “Antonio Ruberti”,

via Ariosto 25 - II piano, stanza A209

Si invitano gli studenti a controllare regolarmente la

bacheca degli avvisi

http://www.dis.uniroma1.it/~bloisi/didattica/labinf1415.html#Avvisi

Pagina 3Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Orari

Lunedì 12.00 – 13.30

Aula 4, via del Castro Laurenziano 7A

Martedì 14.00 – 17.15

Aula 15, Laboratorio Didattico via Tiburtina 205

Mercoledì 12.00 – 13.30

Aula 4, via via del Castro Laurenziano 7A

Pagina 4Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Sommario – Unità 6

• Memoria, indirizzamento e puntatori• Tipo void * e conversioni sui puntatori

• Gestione dinamica della memoria

• Tempo di vita delle variabili allocate

dinamicamente

• Problemi di deallocazione della memoria

• Passaggio dei parametri tramite puntatori

Pagina 5Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Tempo di vita delle variabili allocate

dinamicamente (1/2)

Per le variabili allocate dinamicamente il tempo di vita

corrisponde al periodo che va

Dal momento in cui la variabile viene allocata

Al momento in cui la variabile viene deallocata.

Il tempo di vita di una variabile allocata

dinamicamente è definito solo al momento

dell'esecuzione del programma.

Pagina 6Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Tempo di vita delle variabili allocate

dinamicamente (2/2)

Se una variabile allocata dinamicamente non viene

deallocata esplicitamente, il suo tempo di vita si

prolunga fino alla terminazione del programma.

Può verificarsi il caso in cui una zona di memoria

allocata non sia più accessibile, in quanto non ci

sono variabili che la “riferiscono”.

Tale zona di memoria rimarrà inutilmente occupata

per tutta la durata del programma.

Pagina 7Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esempio: tempo di vita variabili

dinamiche

int* creaint(int a) {

int* temp = malloc(sizeof(int));

*temp = a;

return temp;

}

int main() {

int* pt2 = creaint(5);

printf("*pt2 = %d\n", *pt2);

}

Pagina 8Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esecuzione: Tempo di vita variabili

dinamiche

Il codice precedente stampa

*pt2 = 5

poiché la variabile allocata dalla funzione creaint

viene restituita alla funzione che l'ha invocata e

rimane accessibile anche al termine dell'esecuzione

della funzione.

Le variabili create dinamicamente non rispettano le

regole di campo di azione.

Pagina 9Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esempio Esaurimento della memoria

// sciupa Memoriaint *temp, k;

for (k = 1; 1 ; k++) {

printf("k = %d\n", k);

temp = malloc(sizeof(int));

}

L'esecuzione comporta una richiesta infinita di

memoria (si noti che la condizione del ciclo è sempre

verificata).

Pagina 10Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esecuzione Esaurimento della memoria

L’esecuzione produrrà una richiesta infinita di memoria che in

C comporta (dopo un numero di cicli piuttosto alto)

l’interruzione dell’esecuzione con un messaggio simile al

seguente:

dynamic(1320) malloc: *** mmap(size=16777216) failed

(error code=12) *** error: can’t allocate region

Nota: Ad ogni ripetizione del ciclo, la memoria allocata al ciclo

precedente risulta inaccessibile.

Pagina 11Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Problemi di deallocazione della memoria

int *pt1;

pt1 = malloc(sizeof(int)); // allocazione della variabile

*pt1 = 1;

printf("*pt1 = %d\n", *pt1); // uso della variabile

free(pt1);

// la locazione di memoria rimane accessibile dopo free!!!printf("after free\n");

printf("*pt1 = %d\n", *pt1);

// la stessa locazione di memoria potrebbe essere ri-allocata!!!int *pt2 = malloc(sizeof(int));

printf("after malloc\n");

printf("*pt2 = %d\n", *pt2);

Pagina 12Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esecuzione

Pagina 13Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Discussione Problemi di deallocazione

della memoriaNell'esempio precedente può verificarsi che la memoria rimanga accessibile anche dopo il rilascio (free) e addirittura

che il suo contenuto sia ancora immutato (anche se non è

garantito).

In aggiunta, la riallocazione immediata potrebbe portare ad avere la variabile pt2 nella stessa posizione della memoria

che aveva pt1 e quindi con lo stesso valore (anche questo

non è garantito).

In ogni caso, entrambe le situazioni sopra delineate vanno

evitate accuratamente, in quanto potrebbero generare errori e

comportamenti instabili del programma.

Pagina 14Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Puntatori appesi

Si consideri il seguente frammento di codice

int *pt1;

pt1 = malloc(sizeof(int));

*pt1 = 1;

printf("*pt1 = %d\n", *pt1);

int *pt2;

pt2 = pt1;

printf("prima di free(pt1)\n");

printf("*pt2 = %d\n", *pt2);

free(pt1);

printf("dopo di free(pt1)\n");

printf("*pt2 = %d\n", *pt2);

Pagina 15Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Questa situazione di puntatore appeso (dangling) deve

essere evitata assolutamente, in quanto fonte di errori difficili

da individuare.

Esecuzione Puntatori appesi

*pt1 = 1

prima di free(pt1)

*pt2 = 1

dopo di free(pt1)

*pt2 = 4001536

In questo caso, il rilascio della memoria puntata dalla variabile pt1 lascia la variabile pt2 puntare a una locazione di

memoria rilasciata e quindi suscettibile di modifiche arbitrarie

da parte del sistema operativo.

Pagina 16Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Passaggio di parametri (1/2)

L’uso di variabili di tipo puntatore consente di

simulare la modalità di passaggio dei parametri per

riferimento.

Nel passaggio di parametri per valore, in genere

utilizzato per i dati di tipo primitivo, il parametro

formale può essere considerato come una variabile

locale che viene inizializzata al momento della

chiamata della funzione con il valore corrispondente

al parametro attuale.

Pagina 17Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Passaggio di parametri (2/2)

Il passaggio di parametro per valore effettuato con

il tipo puntatore consente di aggirare una proprietà

cruciale del passaggio di parametri per valore, cioè

la garanzia che la funzione non abbia effetti sul

programma chiamante (a eccezione della

restituzione del valore calcolato).

Pagina 18Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esempio Passaggio parametri

puntatore

void swap(int *a, int *b) {

int temp;

temp = *a;

*a = *b;

*b = temp;

}

Pagina 19Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

int main (){

int x, y;

x = 12; y = 27;

printf("x = %d\n", x);

printf("y = %d\n", y);

swap(&x, &y);

printf("after swap\n");

printf("x = %d\n", x);

printf("y = %d\n", y);

}

Pagina 20

Esempio Passaggio parametri

puntatore

Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esecuzione

x = 12

y = 27

after swap

x = 27

y = 12

Pagina 21Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Passaggio parametri puntatore

Nonostante il passaggio di parametri sia per valore, il risultato dell’esecuzione della funzione swap consiste proprio nel

modificare il valore di due variabili del programma principale.

Passando alla funzione i puntatori a due variabili è possibile

modificare il valore delle variabili puntate, anche se il valore

delle variabili puntatore rimane inalterato.

L’uso dei puntatori nel passaggio di parametri per valore

consente di effettuare in pratica il passaggio di parametri per

riferimento.

Pagina 22Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Passaggio per valore VS passaggio

tramite puntatori

void swap(int *a, int *b) {

int temp;

temp = *a;

*a = *b;

*b = temp;

}

swap(&x, &y);

void swapVal(int a, int b) {

int temp;

temp = a;

a = b;

b = temp;

}

swapVal(x, y);

Cosa succede se si invoca swapVal(&x, &y); ?

definizione invocazione

definizione invocazione

Pagina 23Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esecuzione

Pagina 24Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esempio Intestazione di funzione con

parametri puntatori

void f(int*, double*);

Parametro formale

di tipo puntatore ad int

Parametro formale

di tipo puntatore a double

Pagina 25Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Chiamata tramite parametri puntatore

(per indirizzo): funzione chiamante

Quando la funzione viene chiamata, devono essere passati

come parametri gli indirizzi delle variabili

• Il passaggio degli indirizzi potrà essere ottenuto applicando l’operatore & alla variabile che deve essere

modificata

• Sono passate le “celle” fisiche dove i valori sono

memorizzati

int a; double b;

a = 2; b = 3.2;

f(&a, &b);

2

3.2

a

b

&a

&b

Pagina 26Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Chiamata per indirizzo

Nell’intestazione della funzione chiamata deve essere usato l’operatore * per le variabili passate

per indirizzo

void f(int *pa, double *pb)

{

*pa = 6;

*pb = 7.4;

}

&a

&b

pa

pb

&pa

&pb

Pagina 27Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Chiamata per indirizzo: esecuzione

int a; double b;

a = 2; b = 3.2;

f(&a, &b);

void f(int *pa, double *pb)

{

*pa = 6;

*pb = 7.4;

}

pa

pb

&pa

&pb

6

7.4

a

b

&a

&b

int *pa = &a; double *pb = &b;

Pagina 28Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Vantaggi del passaggio per riferimento

Il passaggio di parametri di tipo puntatore è

particolarmente utile quando i dati che devono

essere scambiati tra funzione chiamata e funzione

chiamante sono voluminosi.

Il passaggio per riferimento risulta molto più

efficiente sia in termini di occupazione di memoria

che di tempo di calcolo (infatti, occorre la copia del

solo puntatore ai dati, non di tutto l’insieme dei

dati).

Pagina 29Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Valori restituiti di tipo puntatore

double* puntatore(double a) {

double *r = malloc(sizeof(double));

*r = a;

return r;

}

int main () {

double *pd = puntatore(5.4);

printf("pd = %p\n", pd);

printf("*pd = %f\n", *pd);

return EXIT_SUCCESS;

}La funzione puntatore crea un puntatore ad

una variabile di tipo double e la inizializza con

il valore passato come argomento

Pagina 30Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esercizi

Esercizio 6.5

Scrivere un programma che legga tre valori in tre distinte variabili small, medium, large, e ne scambi i valori in

modo da avere il più grande nella variabile large, il più

piccolo nella variabile small ed il restante nella variabile

medium. Definire una funzione per lo scambio dei tre valori

che utilizzi il passaggio di parametri puntatore.

Pagina 31Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Esercizi

Esercizio 6.6

Scrivere una funzione che dati due valori interi a e b

restituisca quoziente e resto della divisione a/b.

Scrivere un programma di prova per tale funzione, che

legga l’input da tastiera.

Pagina 32Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Appendice: memoria

Memoria

0

n

La memoria del calcolatore

può essere idealmente

descritta come un insieme di

celle ORDINATO

UNIVOCAMENTE

Pagina 33Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Appendice: assegnazione

int x = 1;0

n

12359156L’istruzione di assegnazione

permette di “scrivere” un

valore all’interno di una cella

simboleggiata da un nome di

variabile

x

Pagina 34Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Appendice: valore di una variabile

int x = 1;

printf("x = %d\n", x);

produce

x = 1

0

n

12359156

Tramite il nome di una variabile è

possibile “leggere” il contenuto della

cella simboleggiata da quella

variabile

x

Pagina 35Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Appendice: indirizzo di una variabile

int x = 1;

printf("&x = %d\n", &x);

produce

&x = 2359156

0

n

12359156

Tramite l’operatore & applicato al

nome di una variabile è possibile

“leggere” l’indirizzo della cella

simboleggiata da quella variabile

x

Pagina 36Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Appendice: puntatore

int x = 1;

int *x_ptr;

x_ptr = &x;

printf("*x_ptr = %d\n", *x_ptr);

printf("&x_ptr = %d\n", &x_ptr);

printf("x_ptr = %d\n", x_ptr);

produce

*x_ptr = 1

&x_ptr = 2359154

x_ptr = 2359156n

12359156

2359154 2359156

x

x_ptr

Pagina 37Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Appendice: valore tramite un puntatore

n

12359156

2359154 2359156

x

x_ptr

Tramite l’operatore * applicato al

nome di un puntatore è possibile

“leggere” il contenuto della cella il

cui indirizzo è contenuto nella cella

simboleggiata da quel puntatore

Pagina 38Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Soluzioni

Esercizio 6.2

Scrivere un programma che legga 10 numeri interi e

restituisca il minimo tra essi, usando variabili di tipo puntatore a int anziché variabili di tipo int.

Pagina 39Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Soluzioni

#include <stdio.h>

#include <stdlib.h>

int main() {

int i, v, min;

int *min_ptr, *v_ptr;

min_ptr = &min;

v_ptr = &v;

printf("inserisci 10 interi:\n");

scanf("%d", v_ptr);

//printf("ho letto %d\n", *v_ptr);

*min_ptr = *v_ptr;

for(i = 1; i < 10; i++) {

scanf("%d", v_ptr);

//printf("ho letto %d\n", *v_ptr);

if(*v_ptr < *min_ptr)

*min_ptr = *v_ptr;

}

printf("minimo = %d\n", *min_ptr);

return EXIT_SUCCESS;

}Pagina 40Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Soluzioni

Esercizio 6.3

Scrivere il programma dell’esercizio precedente tramite

allocazione dinamica della memoria. Deallocare la

memoria utilizzata prima della terminazione del

programma.

Pagina 41Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Soluzioni

#include <stdio.h>

#include <stdlib.h>

int main() {

int i, *min, *v;

min = malloc(sizeof(int));

v = malloc(sizeof(int));

printf("inserisci 10 interi:\n");

scanf("%d", v);

//printf("ho letto %d\n", *v);

*min = *v;

for(i = 1; i < 10; i++) {

scanf("%d", v);

//printf("ho letto %d\n", *v);

if(*v < *min)

*min = *v;

}

printf("minimo = %d\n", *min);

free(v); free(min);

return EXIT_SUCCESS;

}Pagina 42Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Soluzioni

Esercizio 6.4

Scrivere una funzione stampaPtr che dato in ingresso un

puntatore ne stampi la dimensione in byte, il valore,

l’indirizzo di memoria ed il valore della variabile puntata.

Scrivere un programma che verifichi il comportamento di stampaPtr.

Pagina 43Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6

Soluzioni

void stampaPtr_int(int **ptr) {

printf("dimensione del puntatore: %d\n",

sizeof(*ptr));

printf("valore del puntatore: %p\n", *ptr);

printf("indirizzo del puntatore: %p\n", &(*ptr));

printf("dimensione della variabile puntata: "

"%d\n", sizeof(**ptr));

printf("valore della variabile puntata: %d\n\n",

**ptr);

}

int main() {

int i = 5, *ptr_i;

ptr_i = &i;

infoPtr_int(&ptr_i);

}

Si provi a scrivere una funzionevoid

stampaPtr_double(double **ptr)

Pagina 44Laboratorio di Informatica

2014/2015

Passaggio parametri puntatore

Unità 6