Barninga Z
a- a+

I puntatori C: gli array

PUNTATORI 

Gli array 

Un array (o vettore) è una sequenza di datidello stesso tipo, sistemati in memoria... in fila indiana.Una stringa è, per definizione, un array dichar. Si possono dichiarare array di int,di double, o di qualsiasi altro tipo. Il risultatoè, in pratica, riservare in memoria lo spazionecessario a contenere un certo numero di variabili di queltipo. In effetti, si può pensare ad un array anchecome ad un gruppo di variabili, aventi tutte identico nome edaccessibili, quindi, referenziandole attraverso un indice. Ilnumero di "variabili" componenti l'arrayè indicato nella dichiarazione: 

int iArr[15];

La dichiarazione di un array è analoga a quella di unavariabile, ad eccezione del fatto che il nome dell'arrayè seguito dal numero di elementi che lo compongono,racchiuso tra parentesi quadre. Quella dell'esempio forzail compilatore a riservare lo spazio necessario a memorizzare15 interi, dunque 30 byte. Per accedere a ciascuno di essioccorre sempre fare riferimento al nome dell'array,iArr: il singolo int desiderato èindividuato da un indice tra parentesi quadre, che ne indicala posizione. 

 

iArr[0] = 12;    iArr[1] = 25;    for(i = 2; i < 15; i++)  iArr[i] = i;    for(i = 0; i < 15;) {  printf("iArr[%d] = %d" ,i,iArr[i]);  i++;    }

Nell'esempio i primi due elementi dell'array sonoinizializzati a 12 e 25, rispettivamente.Il primo ciclo for inizializza i successivi elementi (dalnumero 2 al numero 14) al valore chei assume ad ogni iterazione. Il secondo ciclo forvisualizza tutti gli elementi dell'array. Premesottolineare che gli elementi di un array sono numerati apartire da 0 (e non da 1), come ci si potrebbe attendere.Dunque, l'ultimo elemento di un array ha indice inferioredi 1 rispetto al numero di elementi in esso presenti. Si vedechiaramente che gli elementi di iArr, dichiaratocome array di 15 interi, sono referenziati con indice che vada 0 a 14

Che accade se si tenta di referenziare un elemento che nonfa parte dell'array, ad esempio iArr[15]? Ilcompilatore non fa una grinza: iArr[15] puòessere letto e scritto tranquillamente... E' ovvio chenel primo caso (lettura) il valore letto non ha alcunsignificato logico ai fini del programma, mentre nel secondocaso (scrittura) si rischia di perdere (sovrascrivendolo)qualche altro dato importante. Anche questa volta ilcompilatore si limita a mettere a disposizione delprogrammatore gli strumenti per gestire la memoria, senzapreoccuparsi di controllarne più di tantol'operato. Per il compilatore, iArr[15] èsemplicemente la word che si trova a 30 bytedall'indirizzo al quale l'array è memorizzato.Che farne, è affare del programmatore[17]. 

Un array, come qualsiasi altro oggetto in memoria, ha unindirizzo. Questo è individuato e scelto dalcompilatore. Il programmatore non può modificarlo, mapuò conoscerlo attraverso il nome dell'arraystesso, usandolo come un puntatore. In C, il nome di un arrayequivale, a tutti gli effetti, ad un puntatore all'areadi memoria assegnata all'array. Pertanto, le righe dicodice che seguono sono tutte lecite: 

int *iPtr;    printf("indirizzo di iArr: %X" ,iArr);    iPtr = iArr;    printf("indirizzo di iArr: %X" ,iPtr);    printf("primo elemento di iArr: %d" ,*iArr);    printf("secondo elemento di iArr: %d" ,*(iArr+1));    ++iPtr;    printf("secondo elemento di iArr: %d" ,*iPtr);

mentre non sono lecite le seguenti: 

++iArr;   // l'indirizzo di un array non puo' essere modificato    iArr = iPtr;    // idem

ed è lecita, ma inutilmente complessa, laseguente: 

iPtr = &iArr;

in quanto il nome dell'array ne restituisce, di per sestesso, l'indirizzo, rendendo inutile l'usodell'operatore & (address of). 

Il lettore attento dovrebbe avere notato che l'indice diun elemento di un array ne esprime l'offset, in terminidi numero di elementi, dal primo elemento dell'arraystesso. In altre parole, il primo elemento di un array haoffset 0 rispetto a se stesso; il secondo ha offset1 rispetto al primo; il terzo ha offset 2,cioè dista 2 elementi dal primo... 

Banale? Mica tanto. Il compilatore "ragiona" sugliarrays in termini di elementi, e non di byte. 

Ripensando alle stringhe, appare ora evidente che esse nonsono altro che array di char. Si differenziano soloper l'uso delle virgolette; allora il problema delconcatenamento di stringhe può essere risolto con unarray: 

    iPtr = &iArr;

iPtr = &iArr;

Nell'esempio abbiamo così a disposizione 100 bytein cui copiare e concatenare le nostre stringhe. 

Puntatori ed array hanno caratteristiche fortemente simili.Si differenziano perché ad un array non puòessere  assegnato un valore[18], e perché unarray riserva direttamente, come si è visto, lo spazionecessario a contenere i suoi elementi. Il numero di elementideve essere specificato con una costante. Non è maipossibile utilizzare una variabile. Con una variabile,utilizzata come indice, si può solo accedere aglielementi dell'array dopo che questo è statodichiarato. 

Gli array, se dichiarati al di fuori di qualsiasi funzione[19], possono essere inizializzati: 

int iArr[] = {12,25,66,0,144,-2,26733};char string[100] = {'C','i','a','o'};float fArr[] = {1.44,,0.3};

Per inizializzare un array contestualmente alla dichiarazionebisogna specificare i suoi elementi, separati da virgole ecompresi tra parentesi graffe aperta e chiusa. Se non siindica tra le parentesi quadre il numero di elementi, ilcompilatore lo desume dal numero di elementi inizializzatitra le parentesi graffe. Se il numero di elementi èspecificato, e ne viene inizializzato un numero inferiore,tutti quelli "mancanti" verranno inizializzati a0 dal compilatore. Analoga regola vale per glielementi "saltati" nella lista di inizializzazione:l'array fArr contiene 3 elementi, aventi valore1.44, 0.0 e 0.3rispettivamente. 

Su string si può effettuare unaconcatenazione come la seguente senza rischi: 

strcat(string," Pippo");

La stringa risultante, infatti, è "CiaoPippo", che occupa 11 byte compreso ilNULL terminale: sappiamo però di averne adisposizione 100. 

Sin qui si è parlato di array monodimensionali,cioè di array ogni elemento dei quali èreferenziabile mediante un solo indice. In realtà, ilC consente di gestire array multidimensionali, nei quali peraccedere ad un elemento occorre specificarne più"coordinate". Ad esempio: 

int iTab[3][6];

dichiara un array a 2 dimensioni, rispettivamente di 3 e 6elementi. Per accedere ad un singolo elemento bisogna, allostesso modo, utilizzare due indici: 

int i, j, iTab[3][6];    for(i = 0; i < 3; ++i)  for(j = 0; j < 6; ++j)iTab[i][j] = 0;

Il frammento di codice riportato dichiara l'arraybidimensionale iTab e ne inizializza a 0tutti gli elementi. I due cicli for sono nidificati,il che significa che le iterazioni previste dal secondovengono compiute tutte una volta per ogni iterazione previstadal primo. In tal modo vengono "percorsi" tutti glielementi di iTab. Infatti il modo in cui ilcompilatore C alloca lo spazio di memoria per gli arraymultidimensionali garantisce che per accedere a tutti glielementi nella stessa sequenza in cui essi si trovano inmemoria, è l'indice più a destra quello chedeve variare più frequentemente. 

E' evidente, d'altra parte, che la memoria èuna sequenza di byte: ciò implica che pur essendoiTab uno strumento che consente di rappresentaremolto bene una tabella di 3 righe e 6 colonne, tutti i suoielementi stanno comunque "in fila indiana".Pertanto, l'inizializzazione di un arraymultidimensionale contestuale alla sua dichiarazionepuò essere effettuata come segue: 

int *tabella[2][5] = {{3, 2, 0, 2, 1},{3, 0, 0, 1, 0}};

Gli elementi sono elencati proprio nell'ordine in cui sitrovano in memoria; dal punto di vista logico, però,ogni gruppo di elementi nelle coppie di graffe piùinterne rappresenta una riga. Dal momento che, comegià sappiamo, il C è molto elastico nelleregole che disciplinano la stesura delle righe di codice, ladichiarazione appena vista può essere spezzata su duerighe, al fine di rendere ancora più evidente ilparallelismo concettuale tra un array bidimensionale ed unatabella a doppia entrata: 

int *tabella[2][5] = {{3, 2, 0, 2, 1},    {3, 0, 0, 1, 0}};

Si noti che tra le parentesi quadre, inizializzandol'array contestualmente alla dichiarazione, non ènecessario specificare entrambe le dimensioni, perchéil compilatore può desumere quella mancante dalcomputo degli elementi inizialiazzati: nella dichiarazionedell'esempio sarebbe stato lecito scriveretabella[][5] o tabella[2][]

Dalle affermazioni fatte discende infoltre che gli elementidi un array bidimensionale possono essere referenziati anchefacendo uso di un solo indice: 

 

int *iPtr;    iPtr = tabella;    for(i = 0; i < 2*5; i++)  printf("%d" ,iPtr[i];

In genere i compilatori C sono in grado di gestire arraymultidimensionali senza un limite teorico (a parte ladisponibilità di memoria) al numero di dimensioni.E' tuttavia infrequente, per gli utilizzi piùcomuni, andare oltre la terza dimensione. 

 



Ti potrebbe interessare anche

commenta la notizia