Array e puntatori in C Diapositive adattate dalle omonime create dalla Dottoressa di Ricerca Giovanna Melideo per il corso di Laboratorio di Algoritmi e Strutture Dati 10/05/2005 LP2-04/05 - Appunti di C 1
Array Sono delle collezioni di variabili tutte dello stesso tipo, individuate da un nome comune, e da una dimensione (nel caso degli array, o vettori) o da una n- pla di dimensione (nel caso di array multi-dimensionali). Le dimensioni vengono indicate racchiudendole fra parentesi quadre. Quando si dichiara una matrice ènecessario indicarne tutte le dimensioni. Forma generale: <tipo elem.> <nome>[<dimensione_1>] [<dimensione_n>] 10/05/2005 LP2-04/05 - Appunti di C 2
Array Esempi: 1.int v[4]; /* dichiarazione array di dim. 4 */ 2.char V[2][3]; /* dichiarazione matrice bidimensionale */ Ogni variabile è accessibile tramite il nome, comune a tutte, specificandone la posizione: l indice del vettore, da 0 alla dimensione -1 n indici, da 0 alla dimensione_i -1, nel caso di array n-dimensionali Esempi: 1.V[0],, V[3] 2.V[0][0], v[0][2], V[1,2] 10/05/2005 LP2-04/05 - Appunti di C 3
Array Inizializzazione in fase di dichiarazione int vettore[3]={0,1,2}; char s[]={ a, b, \0 }; char s[]= ab ; double V[][3] = {{3,2,0}{4,5,9}}; Quando l elenco di inizializzatori èpiù breve della dimensione i restanti elementi vengono inizializzati a zero Se si omette la dimensione, allora viene assegnato il numero di valori di inizializzazione 10/05/2005 LP2-04/05 - Appunti di C 4
Array e puntatori q È importante sapere come vengono memorizzate le matrici sulla macchina per poterle usare correttamente sfruttando a fondo le caratteristiche del C: Gli array vengono memorizzati in locazioni di memoria contigue. sia A un array di interi (supponiamo che ogni intero occupi 2 byte): se l elemento A[0] viene memorizzato a partire dalla locazione di memoria 1000, allora l elemento A[1] sarà memorizzato a partire dall indirizzo 1002, A[2] all indirizzo 1004, ecc. Le matrici sono considerate array di array. Vengono memorizzate disponendo le righe (che sono array e quindi memorizzati su locazioni di memoria contigue) una di seguito all altra. se M è una matrice di 4 righe e 3 colonne di interi (int M[4][3];) ogni elemento occuperà 2 byte di memoria. Se M[0][0] viene allocato nella posizione 5000, allora M[0][1] sarà allocato nella posizione 5002, M[0][2] nella posizione 5004. M[1][0] (il primo elemento della seconda riga) sarà memorizzato nella locazione successiva a quelle occupate dall ultimo elemento della riga precedente (M[0][2]): la locazione 5004+2=5006. 10/05/2005 LP2-04/05 - Appunti di C 5
Array e puntatori Se M è una matrice di n righe ed m colonne, la formula per individuare la locazione di memoria dell elemento M[i][j] (di qualunque tipo sia la matrice) è la seguente: &M[0][0]+i*m+j l indirizzo di memoria del primo elemento, più i volte il numero di elementi presenti su ogni riga, più j Le operazioni aritmetiche sui puntatori tengono conto del tipo di dato a cui punta la variabile. Esempio: se A è una variabile intera memorizzata a partire dalla locazione di memoria 2000, e PA è un puntatore ad A ( PA = &A; ), allora PA+1 punterà alla locazione di memoria 2002 (e non a 2001). 10/05/2005 LP2-04/05 - Appunti di C 6
Gli array ed i puntatori hanno dunque una strettissima parentela in C: nella rappresentazione interna di array e matrici, il compilatore infatti si riconduce sempre ad una notazione che fa uso di puntatori, anche dove nel programma era stato fatto uso di una notazione con indici. L uso dei puntatori al posto degli indici rende il programma più efficiente. Il nome di un array èun puntatore costante al primo elemento di un array: arr == & arr[0] Si ha un equivalenza d uso e di notazione Array e puntatori 10/05/2005 LP2-04/05 - Appunti di C 7
Array e puntatori Sia arr il nome di un array di elementi di tipo T e ptr un puntatore a elementi di tipo T: ptr=&arr[0]; èequivalente a ptr=arr; dopo aver posto ptr=arr; posso accedere all elemento i di un array nei seguenti modi, tutti equivalenti: ptr[i], *(arr+i), arr[i], *(p+i) l indirizzo dell elemento di indice i si può ottere come: &arr[i], arr+i 10/05/2005 LP2-04/05 - Appunti di C 8
Array e puntatori Tuttavia un puntatore è una variabile ma il nome di un array è costante. Ne segue che: ptr++ e ptr=arr sono espressioni valide ma arr++ e arr=ptr non sono valide. 10/05/2005 LP2-04/05 - Appunti di C 9
Aritmetica degli indirizzi Se p1 e p2 sono puntatori ad elementi dello stesso array o al primo elemento oltre la fine di un array, gli operatori di confronto (==,!=, <, >=,<=, >) funzionano correttamente Inoltre se p1 < p2, allora p2-p1+1 è il numero di elementi da p1 a p2, estremi inclusi Ogni puntatore può essere confrontato con 0 per stabilire se è valido o meno Esercizio: trovare il valore massimo tra gli elementi di un array di interi compresi tra il primo e il primo elemento di valore 5 10/05/2005 LP2-04/05 - Appunti di C 10
Array come parametri di funzioni Poiché il nome dell array è un puntatore al primo elemento, passarlo come argomento ad una funzione equivale a passare un puntatore al primo elemento dell array Se alla funzione chiamata serve conoscere la dimensione, essa deve essere passata come parametro separato double somma(double a[], int n) { /* n èla dimensione di a[] */ int i; double s=0; for (i=0; i<n; ++i) s=s+a[i]; return s; } equivale a double somma(double *a, int n); se vèun array di double, possibili chiamate sono: somma(&v[0],88); somma(v,88); somma(&v[i],5); somma(v+i,5); 10/05/2005 LP2-04/05 - Appunti di C 11
Array come parametri di funzioni La copia è sempre per valore e all interno della funzione chiamata il parametro è assegnato a una variabile locale C è coerenza con il passaggio di parametri in C Tuttavia l effetto è di passare alla funzione l indirizzo di un array esterno alla funzione stessa Se la funzione modifica l array, modifica l array esterno non una copia locale Ciò è auspicabile per ragioni di efficienza in quanto la creazione di una copia locale è un operazione che richiede del tempo In altri linguaggi, meno efficienti, è possibile la copia per valore dell array 10/05/2005 LP2-04/05 - Appunti di C 12
Array come parametri di funzioni Naturalmente è possibile anche in C usare una copia locale, ma la copia deve essere inizializzata esplicitamente: double lavora_su_copia(double a[], int n) { int i; double s=0, copia_array[n]; /* SOLO in C99 */ for (i=0; i<n; ++i) copia_array[i]=a[i]; } In C89 si deve dichiarare copia_array[n] dove N è una costante e si deve essere certi che N sia maggiore di ogni possibile valore di n 10/05/2005 LP2-04/05 - Appunti di C 13
Array come parametri di funzioni E possibile passare come parametro un sotto-vettore double f(double a[ ]) { } /* o anche double f(double *a) { }*/ Nel chiamante, se lavoro èun array di elemnti double, si può chiamare f con il sotto-vettore che inizia a partire dall elemento k: sum = f ( lavoro + k); /* o anche sum = f ( & lavoro[ k ]); */ Se si è certi che un vettore è in realtà un sotto-vettore, si può accedere a elementi esterni al sotto-vettore ma contenuti nel vettore utilizzando indici negativi a[ -1 ] /* accede all elemento che precede il primo elemento del sotto-vettore */ 10/05/2005 LP2-04/05 - Appunti di C 14
void scambia(int *,int *); Ordinamento di valori: Bubble-sort void bubble (int a[], int n) { int i,j; for(i=0; i<n-1; ++i) for (j=n-1; j>i; --j) if (a[j-1]>a[j]) scambia(&a[j-1], &a[j]); /* scambia(a+j-1, a+j); */ } void scambia(int *x, int *y) { int app; app = *x; *x = *y; *y = app; return; } 10/05/2005 LP2-04/05 - Appunti di C 15