Prof.Ing.S.Cavalieri Puntatori e Heap in Linguaggio C. Puntatori e Heap

Documenti analoghi
Allocazione dinamica della memoria

Ogni variabile in C è una astrazione di una cella di memoria a cui corrisponde un nome, un contenuto e un indirizzo.

! Per quanto sappiamo finora, in C le variabili sono sempre definite staticamente

Parametri Formali di una Funzione e Record di Attivazione

Unità Didattica 4 Linguaggio C. Vettori. Puntatori. Funzioni: passaggio di parametri per indirizzo.

Allocazione Dinamica. Allocazione Statica. malloc() La funzione malloc()

Il linguaggio C. Puntatori e dintorni

Fondamenti di Informatica

Strutture Dati Dinamiche

Fondamenti di Informatica T. Linguaggio C: i puntatori

Il puntatore. Il puntatore

Corso di Fondamenti di Informatica. Puntatori e Allocazione Dinamica

Gestione dinamica della memoria

Puntatori. Unità 6. Domenico Daniele Bloisi. Corso di Fondamenti di Informatica Ingegneria delle Comunicazioni BCOR Ingegneria Elettronica BELR

Introduzione al C. Unità Gestione Dinamica della Memoria

Puntatori. Unità 6. Corso di Laboratorio di Informatica Ingegneria Clinica BCLR. Domenico Daniele Bloisi

L Allocazione Dinamica della Memoria

Allocazione statica della memoria

Allocazione dinamica della memoria

Definizione Allocazione e deallocazione di variabili Allocazione e deallocazione di vettori

Laboratorio di Informatica Ingegneria Clinica Lezione 14-16/11/2011

Il linguaggio C. Puntatori e dintorni

La gestione della memoria dinamica Heap

Introduzione ai puntatori in C Definizione

Laboratorio di Informatica

I puntatori. Un puntatore è una variabile che contiene l indirizzo di un altra variabile. puntatore

L'allocazione dinamica della memoria

File binari, Operazioni sui File binari, Allocazione dinamica della memoria

Perché il linguaggio C?

Uso avanzato dei puntatori Allocazione dinamica della memoria

Puntatori. Fondamenti di Programmazione

Allocazione della memoria. Allocazione dinamica della memoria. Allocazione della memoria. Allocazione automatica

Stringhe e allocazione dinamica della memoria

Allocazione Dinamica della Memoria

Linguaggio C: PUNTATORI

Il linguaggio C. Puntatori e Array

Laboratorio di Programmazione: Linguaggio C Lezione 21 del 19 maggio 2014

Linguaggio C - sezione dichiarativa: costanti e variabili

Introduzione al linguaggio C Puntatori

Allocazione Dinamica della Memoria

Struttura dei programmi C

Informatica 1. Corso di Laurea Triennale in Matematica. Gianluca Rossi

La Gestione della Memoria. Carla Binucci e Walter Didimo

Programmazione (imperativa)

Lezione 21 e 22. Valentina Ciriani ( ) Laboratorio di programmazione. Laboratorio di programmazione. Lezione 21 e 22

Primi passi col linguaggio C

Lezione 8 Struct e qsort

Non ci sono vincoli sul tipo degli elementi di un vettore Possiamo dunque avere anche vettori di

Verso i puntatori: Cosa è una variabile?

Allocazione dinamica della memoria - riepilogo

Esercizio 2: Algebra dei Puntatori e Puntatori a Puntatori

Applicando lo stesso meccanismo al tipo puntatore, possiamo dichiarare un array di puntatori:

Mini-dispensa sui puntatori in C

Struct, enum, Puntatori e Array dinamici

Compendio sottoinsieme del C++ a comune col C. (Libreria standard, Input/Output, Costanti, Dichiarazioni e typedef, Memoria Dinamica)

Esiste però anche un ambiente globale: quello dove tutte le funzioni sono definite. Qui si possono anche definire variabili, dette variabili globali

Il sistema C è formato dal linguaggio C, dal preprocessore, dal compilatore, dalle librerie e da altri strumenti di supporto.

Fondamenti di Informatica T. Linguaggio C: i puntatori

Corso di Fondamenti di Informatica

IL PRIMO PROGRAMMA IN C

Università degli Studi di Cassino e del Lazio Meridionale Corso di Fondamenti di Informatica Allocazione dinamica di memoria

Linguaggio C: puntatori

Le strutture. Una struttura C è una collezione di variabili di uno o più tipi, raggruppate sotto un nome comune.

Puntatori in C Lucidi della Pof.ssa Pazienza

Esercizi Array. Parte 7. Domenico Daniele Bloisi. Corso di Fondamenti di Informatica Ingegneria delle Comunicazioni BCOR Ingegneria Elettronica BELR

Variabili e Istruzioni

Input/Output. Lettura e scrittura Caratteri e Stringhe: Terminale e file. Input/output. caratteri stringhe formattato ascii binari

Laboratorio di Calcolo Linguaggi di programmazione

Array. Parte 7. Domenico Daniele Bloisi. Corso di Fondamenti di Informatica Ingegneria delle Comunicazioni BCOR Ingegneria Elettronica BELR

Il linguaggio C Strutture

Appunti del corso di Informatica 1 (IN110 Fondamenti) 5 Rappresentazione delle informazioni

POINTERS. Una variabile pointer è una variabile che ha come valore un indirizzo di memoria.

Puntatori. Un puntatore contiene un numero che indica la locazione di memoria dove è presente la variabile puntata

Problema. Vettori e matrici. Vettori. Vettori

Ottenere una modifica del parametro attuale

Implementazione di Liste puntate

Allocazione dinamica

Input/output da file I/O ANSI e I/O UNIX FLUSSI E FILE FLUSSI FLUSSI di TESTO FLUSSI BINARI FILE

Esercizi di programmazione in linguaggio C English Dictionary

Puntatori in C. Puntatori. Variabili tradizionali Esempio: int a = 5; Proprietà della variabile a: nome: a

Inside C : Puntatori. Indirizzo: operatore & p = &v; x = a; Puntatori Referenziazione e Dereferenziazione Arrays

Introduzione al C++ (continua)

Esercizio 2 (punti 7) Dato il seguente programma C: #include <stdio.h> int swap(int * nome, int length);

Argomenti Avanzati.! I puntatori! Stack! Visibilità delle Variabili

Esercizi Array Corso di Fondamenti di Informatica Ingegneria delle Comunicazioni BCOR Ingegneria Elettronica BELR

Lezione 8. Sottoprogrammi

Allocazione dinamica. VLA, malloc() e dintorni

Architettura dei calcolatori e sistemi operativi. M2 Organizzazione della memoria virtuale Struttura dello spazio virtuale kernel e utente

Le operazioni di allocazione e deallocazione sono a carico del sistema.

Corso di Informatica

LE STRUTTURE DATI PARTE 2: RECORD. Prof. G. Ciaschetti

Elementi di Informatica A. A. 2016/2017

Consideriamo un vettore allocato dinamicamente

Calcolatori Elettronici Lezione A4 Programmazione a Moduli

Tipi di dati strutturati e Linguaggio C. Record o strutture Il costruttore struct in C

I puntatori e l allocazione dinamica di memoria

$QDOLVLGHOSURJUDPPDTXDGUDWR

System call per la gestione di processi

ESECUZIONE DI PROGRAMMI C SU MACCHINE REALI. Docente: Giorgio Giacinto AA 2008/2009. formalizzazione degli algoritmi in linguaggio C

Alla variabile pi verrà assegnato come valore l'indirizzo di una variabile di tipo int:

Transcript:

Puntatori e Heap 1.Cosa Sono i Puntatori? I puntatori sono fondamentalmente delle variabili, come quelle intere, reali e carattere. Tuttavia, l unica differenza consiste nel fatto che essi non contengono una valore numerico od alfanumerico, ma un puntatore (ossia un indirizzo) alla locazione di memoria dove è memorizzato un certo valore. Come viene definito un puntatore nel linguaggio C? E molto semplice. La definizione di una variabile puntatore avviene nello stesso modo con cui si definisce una variabile, eccetto che dobbiamo aggiungere un asterisco tra il tipobase e il nome della variabile puntatore. Il simbolo asterisco permette di definire una variabile puntatore e specificare il tipo di dato che è contenuto nell area di memoria puntata dalla variabile puntatore. In altri termini, quando si definisce una variabile puntatore bisogna fin dall inizio specificare che tipo di dato (ad esempio intero, reale o carattere) verrà contenuto nell area di memoria il cui indirizzo è contenuto nella variabile puntatore. Per esempio, il codice seguente crea due puntatori, entrambi puntano ad un intero: int *pnumberone, *pnumbertwo; Adesso facciamo puntare questi puntatori a qualcosa: int NumberOne, NumberTwo; pnumberone = &NumberOne; pnumbertwo = &NumberTwo; L operatore & (ampersand o e-commerciale) deve essere letto come l indirizzo di (Addressof) e restituisce l indirizzo di memoria della variabile e non la variabile. Nell esempio precedente pnumberone è assegnata con l indirizzo della variabile NumberOne, in altre parole punta a tale variabile. Ora, se desideriamo riferirci all'indirizzo di NumberOne, possiamo usare pnumberone. Se desideriamo riferirci al valore di NumberOne da pnumberone, dovremmo scrivere *pnumberone. 1

L operatore * deve essere letto come il contenuto della locazione di memoria puntata da. L operatore * prende il nome di operatore di dereference. 1.1.Che cosa abbiamo imparato finora, un esempio Vediamo un primo esempio per mettere in pratica quanto fino finora. #include <stdio.h> /* definisco le variabili: */ int nnumber; int *ppointer; /* ora, diamogli un valore:*/ nnumber = 15; ppointer = &nnumber; /* stampiamo il valore di nnumber: */ printf( "\n nnumber e' uguale a : %d ",nnumber); /* ora, alteriamo nnumber per mezzo di ppointer: */ *ppointer = 25; /* proviamo che nnumber è stato cambiato e stampiamolo nuovamente:*/ printf("\n nnumber e' uguale a: %d \n ",nnumber); Leggi, scrivi in un editor e compila il precedente codice d esempio; assicurati di aver capito perché funziona. 1.2.Cosa succede nella memoria? Consideriamo il seguente esempio: int n=4; int *p; p=&n; *p=3; 2

Cerhiamo di capire cosa succede nella memoria del computer. Come verrà detto più avanti, la memoria che andremo ad esplorare è l Area Dati della memoria assegnata al programma utente. Le definizioni int n=4 e int *p, determinano la presenza di due locazioni di memoria allocate nell area dati, come mostrato nella seguente figura. n p AB01 AB02 AB03 Come si vede, è stato ipotizzato che entrambe le variabili occupino 2 bytes; in realtà nella maggior parte degli ambienti di compilazione in ANSI C, gli int occupano 4 bytes e i puntatori sono indirizzi anch essi di 4 byte. Solo per semplicità, nel seguito si supporrà che la lunghezza di una variabile puntatore sia di 2 bytes. Nella figura sono anche indicati gli indirizzi (in esadecimale) di ciascun byte. Si ricordi che l indirizzo della variabile n è per definizione l indirizzo del primo byte, cioè. Analogamente l indirizzo di p è AB02. Si ricordi ancora che tali indirizzi vengono fissati sia in fase di compilazione (viene fissato un indirizzo relativo a partire da un indirizzo base o di impianto) sia in quella di esecuzione (dove viene deciso l indirizzo di impianto). Le istruzioni: p=&n; *p=3; hanno il seguente effetto in memoria: n AB01 3 p AB02 AB03 Si consideri il seguente esempio: int x=-57, y=25; int *p; p=&y; x=*p; 3

Cerhiamo di capire cosa succede nella memoria del computer. Le definizioni delle variabili x,y,p, determinano la presenza di tre locazioni di memoria allocate nell area dati, come mostrato nella seguente figura. x AB01-57 y p AB02 AB03 AB04 AB05 25 Le istruzioni: p=&y; x=*p; hanno il seguente effetto in memoria: x AB01 25 y p AB02 AB03 AB04 AB05 25 AB02 2.Allocazione Dinamica L allocazione dinamica è un concetto chiave. E usata per allocare la memoria, ossia riservarla per contenere determinati valori, ed assegnarne l indirizzo di partenza ad un puntatore. Il seguente codice dimostra come allocare la memoria destinata a contenere un numero intero: #include<stdio.h> #include<stdlib.h> int *pnumber; pnumber = (int *) malloc(sizeof(int)); 4

La prima linea dichiara il puntatore pnumber. Nel main, l unica istruzione presente, alloca la memoria per un intero ed assegna a pnumber tale indirizzo (fa puntare pnumber alla memoria appena allocata). Nel seguito è proposto un altro esempio, questa volta utilizzando un char: #include<stdio.h> #include<stdlib.h> char *pstring; pstring = (char *) malloc(sizeof(char)); La formula è la stessa, l unica differenza è il tipobase. In entrambi gli esempi, è stato fatto uso della funzione di libreria malloc(). Essa è definita nel file stdlib.h, che dovrà dunque essere sempre incluso nel programma. La funzione malloc(), richiede come parametro attuale, la dimensione dello spazio di memoria che deve essere allocato; negli esempi mostrati, tale dimensione è fornita tramite il comando sizeof(tipobase), che fornisce il numero di byte occupato dal tipobase. La funzione malloc() restituisce un generico puntatore all area di memoria allocata; nel caso in cui non riesca ad allocare memoria, la funzione ritorna NULL. Come si vede dagli esempi, il valore del puntatore ritornato dalla funzione malloc() deve essere sottoposto ad una funzione di cast, convertendolo nel tipo del puntatore che si desidera avere (puntatore ad int e puntatore a char nei due esempi). La caratteristica fondamentale dell allocazione dinamica, consiste nel fatto che la memoria allocata tramite la funzione malloc() viene rilasciata (resa disponibile per altri usi) solo quando essa viene espressamente rilasciata tramite l uso di una opportuna funzione di libreria, free(), o a quando l intero programma utente non termina. Quindi, se consideriamo l esempio successivo: #include <stdio.h> #include<stdlib.h> int *ppointer; ppointer = (int *)malloc(sizeof(int)); *ppointer = 25; printf("\nvalore di *ppointer = %d ", *ppointer); 5

la memoria allocata rimane intatta fino a quando il programma non termina. Quindi la memoria allocata con il comando malloc è lasciata intatta, non viene mai cancellata automaticamente, ossia la memoria rimarrà occupata per tutta l esecuzione del programma. In questo modo, se la memoria che abbiamo allocato non ci serve più, si sprecherà lo spazio che altre parti del nostro programma potrebbero usare. Una soluzione a ciò è il rilascio della memoria precedentemente allocata tramite la funzione free(). L uso è semplicissimo, basti utilizzare la funzione free(), come segue: free(ppointer); ossia specificando la variabile puntatore relativa all area di memoria precedentemente allocata. Si noti che la funzione free() dealloca l'area puntata dal puntatore, ma non annulla il puntatore, ossia esso non viene posto a NULL, ma viene lasciato al valore attuale. Come mostrato negli esempi precedenti, le funzioni malloc() e free() sono definite in stdlib.h, che bisogna dunque includere sempre nei programmi. 2.1.Dove viene allocata la Memoria? Cerchiamo di capire adesso quale è lo spazio di memoria riservato per l allocazione/rilascio di memoria dinamica. Per capirlo basta pensare che a ciascun programma utente viene assegnata una porzione di memoria, che è automaticamente divisa in quattro porzioni: area del codice contiene il codice del programma area statica che contiene le variabili statiche area heap disponibile per allocazioni dinamiche area stack contiene i record di attivazione delle funzioni (variabili locali e parametri). Per capire meglio il contenuto dell area stack si veda la dispensa Record di Attivazione relativa al Passaggio dei Parametri. Delle quattro aree sopramenzionate, è chiaro che l area heap viene utilizzata per l allocazione di memoria dinamica. Si consideri la seguente figura: 6

Area Programma Area Statica Area Dati Heap Stack Come è visibile dalla figura, le dimensioni delle aree programma e dati sono fisse e sono decise in fase di compilazione. Infatti, tali dimensioni corrispondono al numero di righe comando del programma e al numero di variabili statiche definite in esso. Le altre due aree (Heap e Stack) non hanno dimensione fissa, ma l area complessiva (pari alla somma delle due) è anch essa fissa e decisa in fase di esecuzione. Il fatto che l Heap e lo Stack non abbiano dimensione fissa significa che tale dimensione varia nel tempo a seconda dell utilizzo delle due aree. In particolare per quanto riguarda l area Heap, essa crescerà quando verranno allocate variabili dinamiche. La sua dimensione si ridurrà, invece, quando una o più variabili dinamiche verranno deallocate. Si consideri il programma già visto in precedenza: 7

#include <stdio.h> #include <stdlib.h> int *ppointer; ppointer = (int *)malloc(sizeof(int)); *ppointer = 25; printf("\nvalore di *ppointer = %d ", *ppointer); Appena il programma viene caricato in memoria per essere eseguito la memoria apparirebbe come mostrato dalla seguente figura: Area Programma Area Statica Heap NULL ppointer Area Dati Stack A seguito dell'esecuzione del main(), l'area Heap cresce per poter allocare un intero, che viene posto pari al valore 25 dall'istruzione *ppointer=25. Area Programma Area Statica ppointer Area Dati Heap 25 AB01 Stack 8

3.Allocazione Dinamica di un Vettore L'allocazione dinamica di un vettore viene realizzata utilizzando una variabile puntatore al tipo di appartenenza di ciascun elemento del vettore (se si vuole allocare un vettore di float, bisogna utilizzare un puntatore ad un float). L'allocazione viene realizzata utilizzando la funzione malloc(), ma specificando la dimensione totale del vettore ossia il prodotto del numero di elementi da allocare per la dimensione di ciascun elemento. Si consideri il seguente programma: #include<stdio.h> #include<stdlib.h> float *v; unsigned int i,n; do printf ("Inserisci il valore di n > 1 "); scanf("%u",&n); while (n<2); v=(float *)malloc(n*sizeof(float)); for (i=0; i<n; i++) printf ("\ninserisci un valore reale "); scanf("%f",&v[i]); for (i=0; i<n; i++) printf ("\nil valore dell'elemento di indice %d e' %f \n",i,v[i]); free(v); Come si vede il programma utilizza la variabile statica v (puntatore a float). Nel main viene chiesta all'utente la dimensione del vettore da allocare (n è la variabile contenete la dimensione). Il programma richiede che n sia maggiore di 1 (vettori di dimensione 0 o 1 non hanno senso!). La funzione malloc() permette di allocare una dimensione di memoria contigua pari al prodotto di n per la dimensione di un float. Il programma continua con il riempimento del vettore allocato e con la visualizzazione del suo contenuto. Si noti che il programma finisce con free(v), che provoca la deallocazione dell'area occupata dal vettore. Anche in questo caso, il comando free() non pone a NULL la variabile v, che rimane al suo attuale valore. 9

Per quanto riguarda l'uso della memoria, la seguente figura mostra l'area statica e l'heap appena il precedente programma viene caricato nell'area programma per essere eseguito. Area Programma NULL Area Statica 0 Heap 0 v i n Area Dati Stack Appena il programma viene eseguito, supponendo che l'utente (ossia chi esegue in quel momento il programma) inserisce 10, l'area dati appare come mostrato nella seguente figura. Area Programma Area Dati Heap Area Statica 0 10 v i n 10*sizeof(float) Stack Come si vede l'heap è stato allargato per allocare uno spazio di memoria contigua avente dimensione pari al prodotto tra 10 e la dimensione di un float. Nella figura è stato supposto che tale area inizi dall'indirizzo. 10