Appunti tratti dal videocorso on-line di Algoritmi e Programmazione Avanzata By ALeXio



Documenti analoghi
L'allocazione dinamica della memoria

L'allocazione dinamica della memoria

I puntatori e l allocazione dinamica di memoria

Programmazione. Laboratorio. Roberto Cordone DI - Università degli Studi di Milano

Strutture. Strutture e Unioni. Definizione di strutture (2) Definizione di strutture (1)

Allocazione dinamica della memoria - riepilogo

Gli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori

Struttura a record. File ad accesso diretto. Modalità di apertura. Modalità di apertura

Funzioni in C. Violetta Lonati

dall argomento argomento della malloc()

Laboratorio di Calcolatori 1 Corso di Laurea in Fisica A.A. 2006/2007

RICERCA DI UN ELEMENTO

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

Fondamenti di Informatica 2

La struttura dati ad albero binario

GESTIONE INFORMATICA DEI DATI AZIENDALI

Corso di Fondamenti di Informatica

Laboratorio di Algoritmi e Strutture Dati

Le funzioni in C. I programmi C sono costituiti da definizioni di variabili e funzioni.

Università di Torino Facoltà di Scienze MFN Corso di Studi in Informatica. Programmazione I - corso B a.a prof.

INFORMATICA - I puntatori Roberta Gerboni

Gestione dei File in C

Il tipo di dato astratto Pila

Lezione 9: Strutture e allocazione dinamica della memoria

Inizializzazione, Assegnamento e Distruzione di Classi

La gestione della memoria

Introduzione al Linguaggio C

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP)

Compito di Fondamenti di Informatica

Programmazione C Massimo Callisto De Donato massimo.callisto@unicam.it

costruttori e distruttori

Una funzione è detta ricorsiva se chiama, direttamente o indirettamente, se stessa. In C tutte le funzioni possono essere usate ricorsivamente.

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

Algoritmi di Ricerca. Esempi di programmi Java

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

puntatori Lab. Calc. AA 2007/08 1

CAPITOLO 7 - SCAMBIO DI MESSAGGI

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

Gestione della memoria centrale

Esempio: dest = parolagigante, lettere = PROVA dest (dopo l'invocazione di tipo pari ) = pprrlogvgante

Università degli Studi di Cassino Corso di Fondamenti di Informatica Puntatori. Anno Accademico 2010/2011 Francesco Tortorella

Esercizio 1. Esercizio 1

Algoritmi e Strutture Dati

(Esercizi Tratti da Temi d esame degli ordinamenti precedenti)

Funzioni. Il modello console. Interfaccia in modalità console

Corso di Laurea in Ingegneria Gestionale Esame di Informatica a.a settembre 2011

void funzioneprova() { int x=2; cout<<"dentro la funzione x="<<x<<endl; }

Tipi primitivi. Ad esempio, il codice seguente dichiara una variabile di tipo intero, le assegna il valore 5 e stampa a schermo il suo contenuto:

Introduzione alla programmazione in C

Le stringhe. Le stringhe

3 - Variabili. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Introduzione ai tipi di dato astratti: applicazione alle liste

Fondamenti di Informatica T-1, 2009/2010 Modulo 2 Prova d Esame 5 di Giovedì 15 Luglio 2010 tempo a disposizione 2h30'

Caratteri e stringhe Esercizi risolti

LINGUAGGI DI PROGRAMMAZIONE

Fondamenti di Informatica T. Linguaggio C: i puntatori

Quotazione compareto( ) Quotazione piurecente( ) Quotazione Quotazione Quotazione non trovato count( )

Sottoprogrammi: astrazione procedurale

Variabili e tipi di dato

Laboratorio di Algoritmi e Strutture Dati

COS È UN LINGUAGGIO? LINGUAGGI DI ALTO LIVELLO LA NOZIONE DI LINGUAGGIO LINGUAGGIO & PROGRAMMA

Laboratorio di programmazione

Gestione dinamica di una pila

Algebra di Boole: Concetti di base. Fondamenti di Informatica - D. Talia - UNICAL 1. Fondamenti di Informatica

Gestione delle stringhe in C

MANUALE D'USO DEL PROGRAMMA IMMOBIPHONE

OTTAVA ESPERIENZA DI LABORATORIO. L elaborazione dei files in C

Visibilità dei Membri di una Classe

Introduzione al linguaggio C Gli array

AXO. Operativo. Architetture dei Calcolatori e Sistema. programmazione di sistema

Linguaggio C - Stringhe

Indirizzo di una funzione. Puntatori a funzioni. Definizione di variabili. Definizione di variabili

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2

Tipi di Dato Ricorsivi

Algoritmo. I dati su cui opera un'istruzione sono forniti all'algoritmo dall'esterno oppure sono il risultato di istruzioni eseguite precedentemente.

Linguaggio C - Funzioni

Fondamenti di Informatica e Laboratorio T-AB T-16 Progetti su più file. Funzioni come parametro. Parametri del main

Sono casi particolari di MCF : SPT (cammini minimi) non vi sono vincoli di capacità superiore (solo x ij > 0) (i, j) A : c ij, costo di percorrenza

MANUALE UTENTE Fiscali Free

Programmazione I / Informatica generale Prova scritta 11 Giugno 2008

APPELLO SCRITTO DI PROGRAMMAZIONE 1 CORSO DI LAUREA IN MATEMATICA UNIVERSITÀ DEGLI STUDI DI MILANO XI.2015

Funzioni matlab per la gestione dei file. Informatica B Prof. Morzenti

3) Il seguente numerale A1F0 in base 16 a quale numero in base 10 corrisponde?

Strutturazione logica dei dati: i file

Tecniche di traduzione da C ad assembly Note generali

INFORMATICA 1 L. Mezzalira

Matematica - SMID : Programmazione Febbraio 2009 FOGLIO RISPOSTE

Corso di Informatica


Il problema del produttore e del consumatore. Cooperazione tra processi

Guida rapida per i docenti all'uso della piattaforma di e-learning dell'istituto Giua

Matlab: Gestione avanzata dei file

LISTE, INSIEMI, ALBERI E RICORSIONE

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Capitolo Quarto...2 Le direttive di assemblaggio di ASM Premessa Program Location Counter e direttiva ORG

Breve riepilogo della puntata precedente:

ZZZ01 Esercizi Vari. Esercizi per preparazione alla prova pratica di laboratorio

Manuale d'uso. Manuale d'uso Primo utilizzo Generale Gestione conti Indici di fatturazione Aliquote...

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2

Transcript:

Appunti tratti dal videocorso on-line di Algoritmi e Programmazione Avanzata By ALeXio 1-La memoria dinamica La scrittura di un programma (indipendentemente dal linguaggio adottato) deve sempre tener conto delle condizioni al contorno, ad esempio in termini di: o prestazioni (ossia velocità di esecuzione) o quantità di memoria richiesta o tempo per lo sviluppo o Quando un programma è in corso di esecuzione, nella memoria principale del sistema vi è un area riservata per i dati ed il codice del programma Esecuzione di un programma Inizialmente il programma è memorizzato nella memoria secondaria Quando riceve il comando di esecuzione, il sistema operativo trasferisce nella memoria principale il codice e riserva lo spazio per le strutture dati Durante l esecuzione, il processore esegue il codice ed opera sulle strutture dati Memoria dati La memoria destinata ai dati può essere suddivisa in due parti: o la memoria allocata staticamente o la memoria allocata dinamicamente Memoria allocata staticamente La memoria necessaria per le variabili globali in C resta occupata dal momento dell attivazione del programma sino al suo termine Non è possibile dimensionare tale memoria secondo le esigenze della singola attivazione Si parla quindi di allocazione statica della memoria #define MAX 1000 struct scheda{ int codice; char nome[20]; char cognome[20]; ; struct scheda vett[max]; vett è dimensionato per eccesso, in modo da poter soddisfare in ogni caso le esigenze del programma, anche se questo usa un numero minore di elementi, quindi in ogni caso vett occupa 42.000 byte Allocazione dinamica Molti linguaggi di alto livello supportano l allocazione dinamica della memoria Questo significa che il programmatore può inserire nel proprio codice delle chiamate a procedure di sistema che

o richiedono l allocazione di un area di memoria o richiedono il rilascio di un area di memoria Il programma è in grado di determinare, ogni volta che è lanciato, di quanta memoria ha bisogno Viene allora chiamata una procedura di sistema, che provvede all allocazione della memoria necessaria In tal modo si permette ad eventuali altri processi che lavorano in parallelo sullo stesso sistema di meglio utilizzare la memoria disponibile Durante l esecuzione, il programma ha bisogno di una quantità variabile di memoria Il programma usa ad ogni istante solo la memoria di cui ha bisogno, provvedendo periodicamente ad allocare o deallocare memoria Richiami sui puntatori Definizione e operatori * e & Le variabili di tipo puntatore permettono di accedere alla memoria in modo indiretto La definizione di una variabile di tipo puntatore richiede di definire il tipo della variabile a cui si punta. int *p; L operatore & permette di risalire dal nome di una variabile al suo puntatore: p = &a; L operatore * permette di accedere alla cella di memoria referenziata da una variabile puntatore: *p = 10; Operazioni sui puntatori o Assegnazione: p = q; p = NULL; o Incremento/decremento: p = p+5; p = p-10; p++; Se p è un puntatore ad intero, dopo questa istruzione p punta all'intero posto 5 interi dopo in memoria Puntatori e vettori In C il nome di una variabile di tipo vettore coincide con il puntatore al primo elemento del vettore Quindi puntatori e nomi di vettori sono intercambiabili Definizioni: int vett[max]; int *p; Inizializzazione: p = vett; p=&vett[0]; Forme equivalenti: vett[0]=10; *p=10; vett[10]=25; *(p+10)=25;

vett[i]=0; *(p+i)=0; *vett=27; p[0]=27; *(vett+3)=0; p[3]=0; Scansione e azzeramento di un vettore: int vett[n]; int *p; p=&vett[0]; for (i=0; i<n; i++) *(p++)=0; Puntatori a struct Qualora una variabile p sia di tipo puntatore a struct, ad essa è applicabile l'operatore ->: p->nome_campo (*p).nome_campo struct scheda{ int codice; char nome[20]; char cognome[20]; ; struct scheda *p; struct scheda vett[n]; p=&vett[0]; for (i=0; i<n, i++) vett[i].codice=0; Equivale a for (i=0; i<n, i++) { p->codice=0; Equivale a (*p).codice=0 p++; Procedure malloc e free Le librerie standard del linguaggio C mettono a disposizione del programmatore varie procedure per la gestione della memoria dinamica Le due principali sono o malloc per allocare memoria o free per deallocare memoria malloc Permette di allocare dinamicamente una certa quantità di memoria void *malloc (int n); malloc richiede al sistema operativo l allocazione di una zona di memoria di dimensione (in byte) pari ad n, e ritorna il puntatore all inizio della zona

void *malloc (int n); Il tipo void * corrisponde ad un puntatore ad un tipo generico malloc richiede al sistema operativo l allocazione di una zona di memoria di dimensione (in byte) pari ad n e ritorna il puntatore all inizio della zona int *punt; int n; punt = (int *)malloc(n); Richiede l allocazione di una zona di memoria di n byte Trasforma il puntatore generico ritornato da malloc in un puntatore a int if (punt == NULL) Verifica che l allocazione sia avvenuta regolarmente { printf ( Errore di allocazione\n ); exit(); Deallocazione Quando si desidera deallocare una zona di memoria si usa la procedura di sistema free: void free (void *) La procedura free rende libera la zona di memoria puntata dal parametro, che deve essere stata precedentemente allocata con una chiamata a malloc int *punt; int n; punt = (int *)malloc(n); if (punt == NULL) { printf ( Errore di allocazione\n ); exit(); free (punt); Dealloca la zona di memoria puntata da punt Allocazione dinamica di vettori Si può quindi: o allocare un vettore in modo dinamico tramite la procedura malloc o usare il puntatore ritornato per accedere al vettore, come si farebbe con il nome di un vettore o deallocare la memoria usata, quando questa non è più necessaria Si vuole scrivere una procedura alloca che: o legge da tastiera un numero n o alloca un vettore di n elementi di tipo struct scheda o inizializza ogni elemento del vettore

Procedura alloca int n; /* variabile globale */ struct scheda *alloca (void) { int i; struct scheda *p; scanf("%d", &n); p=(struct scheda *)malloc(n*sizeof(struct scheda)); L peratore sizeof ritorna il numero di byte necessari per la memorizzazione di una variabile del tipo specificato if (p==null) return (NULL); for (i=0; i<n; i++) { p[i].codice=0; strcpy(p[i].nome, ""); strcpy(p[i].cognome, ""); return (p); Allocazione dinamica di stringhe In C le stringhe sono memorizzate sotto forma di vettori di caratteri usando '\0' come carattere di fine stringa Quando si deve memorizzare una stringa di n caratteri si può quindi usare un vettore allocato staticamente di lunghezza MAX>n oppure allocare dinamicamente un vettore di lunghezza n+1 byte Si vuole scrivere una procedura leggi che legge da tastiera i dati relativi ad n schede e li memorizza nel vettore precedentemente allocato, allocando dinamicamente la memoria necessaria per i campi nome e cognome Definizione di struct scheda II o struct scheda{ int codice; char *nome; char *cognome; ; o Procedura leggi int leggi (struct scheda *p) { int i, val; char nome[max], cogn[max]; for (i=0, i<n; i++) { scanf ("%d %s %s\n", &val, nome, cogn); p[i].codice=val; p[i].nome=strdup(nome); if (p[i].nome == NULL) return (ERRORE); p[i].cogn=strdup(cogn); if (p[i].cogn == NULL) return (ERRORE); return (OK); I campi nome e cognome diventano puntatori

Procedura strdup o char *strdup (char *str) { int len; char *p; len=strlen (str); p=(char *)malloc((len+1)*sizeof(char)); if (p==null) return (NULL); strcpy (p, str); return (p); Si vuole scrivere una procedura libera, che dealloca il vettore di n strutture passato come parametro Prima di deallocare il vettore è necessario deallocare la memoria usata per le stringhe Procedura libera o void libera (struct scheda *p) { int i; for (i=0; i<n; i++) { free (p[i].nome); free (p[i].cogn); free (p); o Procedura libera (vers. 2) void libera (struct scheda *p) { int i; struct scheda *q; q=p; for (i=0; i<n; i++) { free (q->nome); free (q->cogn); q++; free (p); o Procedura libera (vers. 3) void libera (struct scheda *p) { struct scheda *q; for (q=p; q<p+n; q++) { free (q->nome); free (q->cogn); free (p); Liste Una lista è una struttura dati basata sull uso dei puntatori e delle procedure di allocazione/deallocazione dinamica della memoria Permette un maggiore flessibilità nell uso della memoria rispetto ad altre strutture dati (ad es. i vettori) al costo di una minore efficienza Una lista è una struttura dati in cui

o ogni elemento viene allocato/deallocato separatamente o ogni elemento è linkato agli altri (e quindi reso accessibile) attraverso puntatori o esiste una variabile (denominata testa) che permette di accedere al primo elemento Conseguenze o Ad ogni istante si utilizza solo la memoria corrispondente agli elementi effettivamente utilizzati o La memoria complessiva richiesta include alcune variabili aggiuntive o Per accedere a ciascun elemento è necessario percorrere la lista Lista semplice Non esiste nessun ordinamento particolare sugli elementi della lista Implementazione in C /* definizione */ struct scheda{ int codice; char *nome; char *cognome; struct scheda *succ; /* definizione testa */ struct scheda *testa=null; Operazioni possibili Le operazioni più comunemente eseguite su una lista sono o Inserimento o Ricerca o Cancellazione Inserimento in testa struct scheda *p; p=(struct scheda *)malloc(sizeof(struct scheda)); if (p==null) error(); /* gestisce la situazione di errore */ p->codice=val; p->nome=strdup(nome); if (p->nome==null) error(); /* gestisce la situazione di errore */ p->cognome=strdup(cognome); if (p->cognome==null) error(); /* gestisce la situazione di errore */ p->succ=testa; testa=p; Procedura inserisci int inserisci (struct scheda *t, int val, char *nome, char *cogn) { struct scheda *p;

p=(struct scheda *)malloc(sizeof(struct scheda)); if (p==null) return (ERRORE); p->codice=val; p->nome=strdup(nome); if (p->nome==null) return (ERRORE); p->cognome=strdup(cognome); if (p->cognome==null) return (ERRORE); p->succ=t; t=p; Il parametro t è modificato, ma il C supporta solo i parametri passati by value! return (OK); Quindi al suo termine questa versione di inserisci lascia il valore di testa invariato! QUINDI: ERRORE! Procedura inserisci int inserisci (struct scheda **t, int val, char *nome, char *cogn) La variabile testa è passata by reference, ossia la procedura riceve il puntatore alla variabile Programma chiamante struct scheda *testa; int ret, val; char nome[max], cognome[max]; scanf ("%d, %s %s\n", &val, nome, cognome); ret=inserisci (&testa, val, nome, cognome); if (ret == ERRORE) error(); Ricerca Si scandisce la lista sino a che si arriva al fondo oppure si trova l elemento cercato Ricerca struct scheda *ricerca (struct scheda *t, int val) { struct scheda *p; p=t; while (p!=null) { if (p->codice==val) return (p); p=p->succ; return (p); Programma chiamante struct scheda *testa, *p; int val;

scanf ("%d\n", &val); p=ricerca (testa, val); if (p == NULL) printf ("Elemento non trovato\n"); else printf("%d %s %s\n", p->codice, p->nome, p->cogn); Liste ordinate Se la procedura di inserimento inserisce il nuovo elemento nella posizione opportuna, la lista è mantenuta ordinata (rispetto ad un certo campo chiave) In tal modo è possibile semplificare le operazioni di ricerca, accedere agli elementi in ordine Inserimento in lista ordinata int inserisci_ord (struct scheda **t, int val, char *nome, char *cogn) { struct scheda *p, *q; /* allocazione nuovo elemento */ p = alloca( val, nome, cogn); if( p == NULL) return(errore); q = *t; /* inserimento in testa */ if( (q == NULL) (q->codice > val)) Lista vuota il nuovo elemento ha valore < del vecchio primo elemento { p->succ=*t; *t=p; return (OK); Inserimento in lista ordinata (2) /* inserimento in mezzo */ while( q->succ!= NULL) { if( q->succ->codice > val) { p->succ=q->succ; q->succ=p; return (OK); q = q->succ; /* inserimento in coda */ p->succ = NULL; q->succ = p; return(ok); Cancellazione La cancellazione di un elemento normalmente richiede o Un operazione di ricerca, che produce il puntatore all'elemento da cancellare o Un operazione di cancellazione vera e propria; questa richiede non solo il puntatore all'elemento da cancellare, ma anche quello all'elemento precedente

Cancellazione int cancella (struct scheda **t, int val) { struct scheda *p, *q; q = *t; if (q==null) /* lista vuota */ return (ERRORE); /* cancellazione in testa */ if (q->codice == val)) { free (q->nome); free (q->cogn); *t=q->succ; free (q); return (OK); Cancellazione (2) /* cancellazione in mezzo o in coda */ while( q->succ!= NULL) { if( q->succ->codice == val) { q->succ=q->succ->succ; free (q->succ->nome); free (q->succ->cogn); free (q->succ); return (0); q = q->succ; Sentinelle Può essere conveniente aggiungere alla lista degli elementi fittizi (detti sentinelle) che permettono di: o semplificare il codice per la gestione delle liste o aumentarne l efficienza (senza cambiare la complessità nel caso peggiore) Sentinelle: liste non ordinate In questo caso si usano solitamente due sentinelle (una in coda ed una in testa) Le sentinelle permettono di semplificare il codice (non si devono più considerare separatamente i casi di inserimento/cancellazione in testa e in coda) Sentinelle: liste ordinate In questo caso le due sentinelle contengono il valore minimo e quello massimo memorizzabili, in tal modo: o si semplifica il codice (non si devono più considerare separatamente i casi di inserimento/cancellazione in testa e in coda) o si rende più veloce l'esecuzione, in quanto si può eliminare il test di fine lista