Array • dichiarazioni e accesso agli elementi • indici di array • cicli for per accesso sequenziale • elementi di array come argomenti di funzioni • array come argomenti di funzioni • ricerca e ordinamento • array multidimensionali 1 Struttura dati collezione di dati correlati, a cui viene associato un unico nome simbolico Array collezione di dati dello stesso tipo; i dati appartenenti all’array sono detti elementi dell’array; gli elementi dell’array vengono memorizzati in celle di memoria contigue 2 Dichiarazione di array double x[8]; associa 8 celle di memoria al nome x; ogni elemento dell’array x può contenere un singolo valore di tipo double 3 Accesso agli elementi dell’array per utilizzare i dati contenuti nell’array, accedo agli elementi specificando il nome dell’array e la posizione dell’elemento nell’array la variabile indiciata x[0] si riferisce al primo elemento dell’array; x[1] si riferisce all’elemento seguente e x[7] all’ultimo elemento l’intero tra parentesi quadre si chiama indice dell’array; il suo valore deve essere compreso tra 0 e numero_di_celle - 1 4 Esempio x[0] x[1] x[2] x[3] x[4] x[5] x[6] x[7] 16.0 12.0 6.0 8.0 printf(“%.1f”, x[0]); x[3] = 25.0; sum = x[0] + x[1]; sum += x[2]; x[3] += 1.0; x[2] = x[0] + x[1]; 2.5 12.0 14.0 -54.5 visualizza 16.0 memorizza 25.0 in x[3] memorizza 28.0 in sum aggiunge 6.0 a sum, il cui contenuto diventa 34.0 aggiunge 1.0 a x[3], il cui contenuto diventa 26.0 memorizza 28.0 in x[2] x[0] x[1] x[2] x[3] x[4] x[5] x[6] x[7] 16.0 12.0 28.0 26.0 2.5 12.0 14.0 -54.5 5 Esempio memorizzazione dei voti degli studenti all’esame di Laboratorio 1 #define NUM_STUDENTI 80 int matr[NUM_STUDENTI]; int voto[NUM_STUDENTI]; array paralleli: due o più array, aventi lo stesso numero di elementi, utilizzati per memorizzare informazioni correlate 6 Esempio punteggio ottenuto da uno studente negli esercizi svolti durante la settimana #define NUM_CLASS_DAYS 5; typedef enum {monday, tuesday, wednesday, thursday, friday} class_day_t; int score[NUM_CLASS_DAYS]; score[tuesday] = 8; 7 Esempio double x[5], sum, y[6]; int factor[11], n, index; posso dichiarare più array in una singola dichiarazione; posso dichiarare insieme array e variabili semplici. 8 Inizializzazione di array E’ possibile inizializzare un array al momento della sua dichiarazione. Se l’array viene inizializzato completamente, posso omettere la dimensione (che verrà dedotta dal numero di elementi nella lista di inizializzazione) int prime_lt_50[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}; 9 Dichiarazione di array sintassi element_type aname[size]; element_type aname[size] = {initialization_list}; element_type aname[ ] = {initialization_list}; esempio double a[A_SIZE]; char vowels[ ] = {‘a’, ‘e’, ‘i’, ‘o’, ‘u’}; 10 Dichiarazione di array Viene allocato spazio in memoria per contenere l’array aname, costituito da size elementi. Ogni elemento può contenere un dato di tipo element_type (es. int, double, char). Si accede ai singoli elementi mediante le variabili indiciate aname[0], aname[1], . . ., aname[size - 1]. La dimensione size è un’espressione costante di tipo int. 11 Dichiarazione di array Nella dichiarazione con inizializzazione, la dimensione size è opzionale; se viene omessa, la dimensione dell’ array è data dalla lunghezza di initialization_list. La initialization_list è formata da una sequenza di espressioni costanti di tipo element_type, separate da virgole. L’elemento 0 dell’array viene inizializzato con il primo valore in initialization_list, l’elemento 1 viene inizializzato con il secondo valore, e così via. 12 Indici di array Gli indici sono utilizzati per manipolare i singoli elementi dell’array. Un indice è un’espressione di tipo int; un indice è valido se assume un valore compreso tra 0 e la dimensione dell’array meno 1. x[0] x[1] x[2] x[3] x[4] x[5] x[6] x[7] 16.0 12.0 6.0 8.0 2.5 12.0 14.0 -54.5 se i vale 3, allora il valore di x[i] è 8.0 se i vale 0, allora il valore di x[i] è 16.0 13 Esempio x[0] x[1] x[2] x[3] x[4] x[5] x[6] x[7] 16.0 12.0 6.0 8.0 2.5 12.0 14.0 -54.5 i = 5; printf(“%d %.1f”, 4, x[4]); stampa 4 e 2.5 (valore di x[4]) printf(“%d %.1f”, i, x[i]); stampa 5 e 12.0 (valore di x[5]) printf(“%.1f”, x[i] + 1); stampa 13.0 (valore di x[5] più 1) printf (“%.1f”, x[i] + i); stampa 17.0 (valore di x[5] più 5) printf (“%.1f”, x[i+1]); stampa 14.0 (valore di x[6]) printf (“%.1f”, x[i+i]); NO (tenta di stampare x[10]) printf (“%.1f”, x[2*i-3]); stampa -54.5 (valore di x[7]) printf (“%.1f”, x[(int)x[4]]); stampa 6.0 (valore di x[2]) 14 Esempio x[0] x[1] x[2] x[3] x[4] x[5] x[6] x[7] 16.0 12.0 6.0 printf (“%.1f”, x[i++]); printf(“%.1f”, x[--i]); x[i - 1] = x[i]; x[i] = x[i + 1]; x[i] - 1 = x[i]; 8.0 2.5 12.0 14.0 -54.5 stampa 12.0 (valore di x[5]) assegna 6 (5 più 1) ad i assegna 5 (6 meno 1) ad i stampa 12.0 (valore di x[5]) assegna 12.0 (valore di x[5]) ad x[4] assegna 14.0 (valore di x[6]) ad x[5] assegnamento illegale 15 Variabili indiciate sintassi aname[subscript]; esempio b[i + 1]; subscript è un’espressione di tipo int; il compilatore valuta subscript, e il valore ottenuto determina a quale elemento dell’array aname ci riferiamo. Nota: il programmatore deve garantire che il valore di subscript sia compreso tra 0 e la dimensione dell’array meno 1; solo in certi casi si verifica un errore a tempo di esecuzione. 16 Cicli for per accesso sequenziale E’ spesso necessario elaborare gli elementi di un array in sequenza, partendo dal primo elemento (es. inizializzazione o stampa del contenuto dell’array, somma degli elementi). Si utilizza un ciclo for, la cui variabile di controllo viene usata come indice dell’array. 17 Cicli for per accesso sequenziale Esempio Memorizzare i quadrati dei numeri da 0 a 10 nell’array square. #define SIZE 11 int square[SIZE], i; for (i = 0; i < SIZE; i++) square[i] = i * i; 18 Cicli for per accesso sequenziale Esempio punteggio ottenuto da uno studente negli esercizi svolti durante la settimana: 9, 7, 5, 3, 1 #define NUM_CLASS_DAYS 5; typedef enum {monday, tuesday, wednesday, thursday, friday} class_day_t; int score[NUM_CLASS_DAYS], cscore; class_day_t today; cscore = 9; for (today = monday; today <= friday; today++) { score[today] = cscore; cscore -=2; } 19 Utilizzo di array per calcoli statistici Programma che prende in input un insieme di dati, ne calcola la media e lo scostamento di ogni singolo dato dalla media. 20 /* * Computes the mean of an array of data and displays * the difference between each value and the mean. */ #include <stdio.h> #include <math.h> #define MAX_ITEM 8 /* maximum number of items */ int main(void) { double x[MAX_ITEM], /* data list */ mean, /* mean (average) of the data */ sum, /* sum of the data */ int i; /* Gets the data */ printf("Enter %d numbers separated by <return>\n> ", MAX_ITEM); 21 for (i = 0; i < MAX_ITEM; scanf("%lf", &x[i]); ++i) /* Computes the sum of all data */ sum = 0; for (i = 0; i < MAX_ITEM; ++i) sum += x[i]; /* Computes and prints the mean */ mean = sum / MAX_ITEM; printf("The mean is %.2f.\n", mean); /* Displays the difference between each item and the mean */ printf("\n Differences between data values and mean\n"); printf("Index Item Difference\n"); for (i = 0; i < MAX_ITEM; ++i) printf("%3d%4c%9.2f%5c%9.2f\n", i, ' ', x[i], ' ', x[i] - mean); return (0); } 22 Elementi di array utilizzati come argomenti di funzioni printf("%3d%4c%9.2f%5c%9.2f\n", i, ' ', x[i], ' ', x[i] - mean); x[i] è passata come argomento di input alla funzione printf; se i = 2, viene stampato il contenuto di x[2] scanf("%lf", &x[i]); l’elemento x[i] è utilizzato come argomento di output dalla funzione scanf; se i = 4, il valore inserito dall’utente viene memorizzato in x[4] 23 Elementi di array utilizzati come argomenti di funzioni void do_it(double arg1, double *arg2_p, double *arg3_p); prototipo di funzione con un parametro di input e due parametri di output do_it(x[0], &x[1], &x[2]); chiamata a funzione che utilizza il primo elemento dell’ array x come argomento di input e il secondo e terzo elemento come argomenti di output 24 Area dati del chiamante [0] [1] [2] [3] [4] [5] [6] [7] Area dati della funzione do_it x arg1 16.0 12.0 6.0 8.0 2.5 12.0 14.0 16.0 arg2_p arg3_p -54.5 25 Array come argomenti a funzioni Se tra gli argomenti di una chiamata a funzione appare un nome di array senza indici, nel corrispondente parametro formale viene memorizzato l’indirizzo del primo elemento dell’array. Nel corpo della funzione utilizzo gli indici per accedere ai singoli elementi dell’array. Poichè la funzione manipola l’array originario, e non una sua copia, ogni assegnamento a un elemento dell’array effettuato nel corpo della funzione effettua una modifica al contenuto dell’array originario. 26 Esempio: fill_array Funzione che setta tutti gli elementi dell’array al valore specificato da in_value. /* * Sets all elements of its array parameter to in_value. * Pre: n and in_value are defined. * Post: list[i] = in_value, for 0 <= i < n. */ void fill_array (int list[], /* output - list of n integers int n, /* input - number of list elements int in_value) /* input - initial value { int i; for } */ */ */ /* array subscript and loop control */ (i = 0; i < n; ++i) list[i] = in_value; 27 Esempio: fill_array Il parametro formale di tipo array e’ dichiarato come segue: int list[] questa dichiarazione non specifica quanti elementi sono contenuti nell’array list. Poichè non viene allocato spazio per contenere una copia dell’intero array, il compilatore non ha bisogno di conoscere la dimensione dell’array passato come parametro. La funzione fill_array può quindi gestire array di interi di qualunque dimensione. 28 fill_array(y, 5, -7); Memoria all’inizio dell’esecuzione di fill_array: Area dati del chiamante [0] y ?? [1] ?? [2] ?? [3] ?? [4] ?? Area dati di fill_array list n 5 in_value -7 i ?? 29 fill_array(y, 5, -7); Memoria al termine dell’esecuzione di fill_array: Area dati del chiamante [0] y -7 [1] -7 [2] -7 [3] -7 [4] -7 Area dati di fill_array list n 5 in_value -7 i 5 30 *list vs list[ ] Le seguenti dichiarazioni di parametri formali sono equivalenti: int list[] int *list Attenzione: se specifichiamo un parametro formale come puntatore, è legale passare come argomento attuale un array dello stesso tipo. 31 Array come parametri di input Il qualificatore const, utilizzato nella dichiarazione di parametri formali di tipo array, informa il compilatore che l’array viene passato in input e non deve essere modificato dalla funzione: int get_max(const int list[], int n) Ogni tentativo di modificare gli elementi dell’array list all’interno della funzione viene segnalato come errore. 32 /* * Returns the largest of the first n values in array list * Pre: First n elements of array list are defined and n > 0 */ int get_max(const int list[ ], /* input - list of n integers */ int n) /* input - number of list elements to examine */ { int i, cur_large; /* largest value so far */ /* Initial array element is largest so far. cur_large = list[0]; */ /* Compare each remaining list element to the largest so far; save the larger */ for (i = 1; i < n; ++i) if (list[i] > cur_large) cur_large = list[i]; return (cur_large); } 33 Array come parametri di input sintassi const element_type array_name[ ] esempio const int list[ ] La parola riservata const indica che la variabile di tipo array è un parametro di input e non deve essere modificata dalla funzione. Poichè il parametro formale corrispondente equivale a un puntatore al primo elemento di array_name, se const viene omesso è possibile modificare gli elementi dell’array passato come argomento. 34 Array come parametri di input Il tipo degli elementi dell’array è element_type. Le [ ] dopo array_name indicano che il parametro è un array. Al momento della chiamata, nel parametro formale array_name verrà memorizzato l’indirizzo del primo elemento dell’array passato come argomento. E’ possibile utilizzare la dichiarazione equivalente const element_type *array_name 35 Ritornare un risultato di tipo array In C il tipo del valore ritornato da una funzione non può essere un array. Per ritornare un oggetto di tipo array è necessario utilizzare un parametro di output di tipo array. La funzione fill_array utilizza l’array list come parametro di output. Esempio: funzione che effettua la somma di due array 36 /* * Adds corresponding elements of arrays ar1 and ar2, storing * the result in arsum. Processes first n elements only. * Pre: First n elements of ar1 and ar2 are defined. * arsum's corresponding actual argument has a declared * size >= n (n >= 0) */ void add_arrays(const double ar1[], /* input */ const double ar2[], /* arrays being added */ double arsum[],/* output - sum of corresponding elements of ar1 and ar2 */ int n) /* input - number of element pairs summed */ { int i; /* Adds corresponding elements of ar1 and ar2 for (i = 0; i < n; ++i) arsum[i] = ar1[i] + ar2[i]; */ } 37 add_arrays(x, y, x_plus_y, 3); Area dati chiamante Area dati add_arrays array x 1.5 2.0 5.1 ar1 n 3 array y 2.0 7.2 0.0 ar2 ?? arsum array x_plus_y ?? ?? 38 operatore & add_arrays(x, y, x_plus_y, 3); nella chiamata a add_arrays non c’è differenza di notazione tra i riferimenti agli array di input x e y e il riferimento all’array di output x_plus_y. A differenza di quanto avviene per i parametri di tipo semplice, parametri di output di tipo array non sono preceduti da &. In C il passaggio di array avviene in entrambi i casi memorizzando l’indirizzo del primo elemento dell’array nel corrispondente parametro formale. 39 Array riempiti parzialmente Alcuni programmi manipolano sequenze di dati di lunghezza diversa. Posso riutilizzare lo stesso array per contenere sequenze diverse: • dichiaro un array di dimensioni sufficienti a contenere la sequenza più lunga • tengo traccia del numero di elementi contenuti nella sequenza che sto utilizzando 40 /* * Gets data to place in dbl_arr until value of sentinel is * encountered in the input. * Returns number of values stored through dbl_sizep. * Stops input prematurely if there are more than dbl_max data * values before the sentinel or if invalid data is encountered. * Pre: sentinel and dbl_max are defined and dbl_max is the * declared size of dbl_arr */ void fill_to_sentinel(int dbl_max, /* input - declared size of dbl_arr */ double sentinel, /* input - end of data value in input list */ double dbl_arr[], /* output - array of data */ int *dbl_sizep) /* output - number of data values stored in dbl_arr */ { double data; int i, status; 41 /* Sentinel input loop */ i = 0; status = scanf("%lf", &data); while (status == 1 && data != sentinel dbl_arr[i] = data; ++i; status = scanf("%lf", &data); } && i < dbl_max) { /* Issues error message on premature exit */ if (status != 1) { printf("\n*** Error in data format ***\n"); printf("*** Using first %d data values ***\n", i); } else if (data != sentinel) { printf("\n*** Error: too much data before sentinel ***\n") printf("*** Using first %d data values ***\n", i); } /* Sends back size of used portion of array *dbl_sizep = i; */ } 42 /* Driver to test fill_to_sentinel function */ #define A_SIZE 20 #define SENT -1.0 int main(void) { double arr[A_SIZE]; int in_use, /* number of elements of arr in use */ i; fill_to_sentinel(A_SIZE, SENT, arr, &in_use); printf("List of data values\n"); for (i = 0; i < in_use; ++i) printf("%13.3f\n", arr[i]); return (0); } 43 Agli array parzialmente riempiti corrispondono 2 grandezze: • la dimensione dell’array, specificata nella dichiarazione • il numero di elementi effettivamente utilizzati Nel main, dopo la chiamata a fill_to_sentinel, la visualizzazione del contenuto dell’array viene effettuata utilizzando la variabile in_use (numero di elementi dell’array che sono stati riempiti) e non A_SIZE (dimensione dichiarata dell’array). Notare la differenza nel passaggio di argomenti di output di tipo semplice (in_use) e di tipo array (arr) nella chiamata a fill_to_sentinel. 44 Pila (stack) Collezione di dati dello stesso tipo. I dati vengono inseriti in cima alla pila. Posso rimuovere solo l’elemento in cima alla pila. Es. pila di vassoi in mensa. push inserisce un nuovo elemento in cima alla pila pop rimuove l’elemento in cima alla pila 45 Pila di caratteri C + 5 C + 5 pop ritorna ‘C’ e trasforma la pila in + 5 push ‘z’ trasforma la pila in z C + 5 46 Implementazione mediante array C + 5 [0] [1] [2] [3] s s_top 5 + C 2 [STACK_SIZE] 47 Implementazione pila vuota s [0] [1] [2] [3] s_top -1 [STACK_SIZE] 48 Funzione push per pile di caratteri void push(char stack[], char item, int *top, int max_size) /* input/output - the stack */ /* input - data being pushed onto the stack */ /* input/output - pointer to top of stack */ /* input - maximum size of stack */ { if (*top < max_size-1) { ++(*top); stack[*top] = item; } } 49 Funzione pop per pile di caratteri char pop(char stack[], int *top) /* input/output - the stack */ /* input/output - pointer to top of stack */ { char item; /* value popped off the stack */ if (*top >= 0) { item = stack[*top]; --(*top); } else { item = STACK_EMPTY; } return (item); } 50 Esempio #define STACK_SIZE 100 #define STACK_EMPTY @ ... char s[STACK_SIZE]; int s_top = -1; /* a stack of characters */ /* stack s is empty */ ... push(s, ‘5’, &s_top, STACK_SIZE); push(s, ‘+’, &s_top, STACK_SIZE); push(s, ‘C’, &s_top, STACK_SIZE); 51 Progetti • programma che prende in input una sequenza di caratteri e la stampa in ordine inverso • programma che prende in input un’espressione aritmetica con parentesi tonde, quadre e graffe e controlla che le parentesi siano bilanciate • programma che prende in input un’espressione in forma postfissa, ne controlla la correttezza e la valuta 52 Ricerca Determinare la posizione di un elemento, detto target, in un array. Ricerca lineare: utilizzo un ciclo per esaminare gli elementi dell’array uno alla volta, confrontandoli con il target; quando trovo un valore uguale al target, esco dal ciclo. Utilizzo un flag per indicare che il valore è stato trovato e posso uscire dal ciclo. 53 Algoritmo di ricerca lineare 1. inizializza il flag per indicare che il target non è ancora stato trovato 2. inizia dal primo elemento dell’array finchè non viene trovato il target e ci sono ancora elementi da esaminare: 4. se l’elemento corrente è uguale al target 5. setta il flag per indicare che il target è stato trovato altrimenti 6. passa al prossimo elemento 7. se il target è stato trovato 8. ritorna l’indice dell’elemento uguale al target altrimenti 54 9. ritorna -1 #define NOT_FOUND -1 /* Value returned by search function if target not found */ /* * Searches for target item in first n elements of array arr * Returns index of target or NOT_FOUND * Pre: target and first n elements of array arr are defined * and n>=0 */ int search(const int arr[], /* input - array to search */ int target, /* input - value searched for */ int n) /* input - number of elements to search */ { int i, found = 0, /* whether or not target has been found */ where; /* index where target found or NOT_FOUND */ 55 /* Compares each element to target i = 0; while (!found && i < n) { if (arr[i] == target) found = 1; else ++i; } */ /* Returns index of element matching target or NOT_FOUND */ if (found) where = i; else where = NOT_FOUND; return (where); } 56 Ricerca su array ordinati Per effettuare la ricerca di un elemento in un array in cui gli elementi sono ordinati posso utilizzare la ricerca binaria. E’ simile al metodo utilizzato per cercare un numero nell’elenco telefonico: • apro l’elenco a metà e guardo il nome a metà pagina • se non è il nome che sto cercando, decido se viene prima o dopo il nome che sto cercando • scelgo la metà appropriata dell’elenco e ripeto i passi precedenti finchè non trovo il nome cercato 57 Algoritmo di ricerca binaria 1. sia bottom l’indice del primo elemento 2. sia top l’indice dell’ultimo elemento 3. pongo found a false 4. ripeti finchè bottom non è maggiore di top e il target non è stato trovato 5. sia middle l’indice dell’elemento a metà strada tra bottom e top 6. se l’elemento alla posizione middle è il target 7. setta found a vero e index a middle altrimenti se l’elemento alla posizione middle è maggiore del target 8. poni top a middle - 1 altrimenti 58 9. poni bottom a middle + 1 Ordinamento Selection sort: per ordinare un array di n elementi (indici da 0 a n-1), cerco l’elemento più piccolo dell’array e lo scambio con l’elemento in posizione 0; a questo punto, la posizione 0 contiene l’elemento più piccolo dell’array. Poi, cerco il più piccolo elemento nel sottoarray con indici da 1 a n-1, lo scambio con l’elemento nella posizione 1, e così via. 59 Algoritmo di selection sort 1. per ogni valore di fill da 0 a n-2 2. cerca index_of_min, l’indice del più piccolo elemento nel sottoarray non ordinato da list[fill] a list[n-1] 3. se fill non è la posizione dell’elemento più piccolo (index_of_min) 4. scambia l’elemento più piccolo con l’elemento nella posizione fill 60 Esempio [0] [1] [2] [3] 61 /* * * * * * * * */ int Finds the position of the smallest element in the subarray list[first] through list[last]. Pre: first < last and elements 0 through last of array list are defined. Post: Returns the subscript k of the smallest element in the subarray; i.e., list[k] <= list[i] for all i in the subarray. get_min_range(int list[], int first, int last); Esercizio: scrivere il corpo di get_min_range 62 /* * Sorts the data in array list * Pre: first n elements of list are defined and n >= 0 */ void select_sort(int list[], /* input/output - array being sorted */ int n) /* input - number of elements to sort */ { int fill, /* first element in unsorted subarray */ temp, /* temporary storage */ index_of_min; /* subscript of next smallest element */ for (fill = 0; fill < n-1; ++fill) { /* Find position of smallest element in unsorted subarray */ index_of_min = get_min_range(list, fill, n-1); /* Exchange elements at fill and index_of_min */ if (fill != index_of_min) { temp = list[index_of_min]; list[index_of_min] = list[fill]; list[fill] = temp; } } } 63 Tempo di esecuzione Il tempo necessario per eseguire un programma può essere misurato utilizzando le funzioni di libreria dichiarate in time.h. clock_t clock(void); restituisce il tempo di cpu utilizzato dal programma dall’inizio dell’esecuzione, espresso in unità di clock. clock_t è un tipo numerico definito in time.h. CLOCKS_PER_SEC numero di unità di clock al secondo. 64 Tempo di esecuzione double start, finish, elapsed; start = (double) clock() / CLOCKS_PER_SEC; ...istruzioni... finish = (double) clock() / CLOCKS_PER_SEC; elapsed = finish - start; 65 Differenza tra clock e time clock_t clock(void); viene utilizzato per calcolare il tempo utilizzato esclusivamente per l’esecuzione del programma. time_t time(time_t *p); viene utilizzato per misurare il tempo trascorso dall’inizio dell’esecuzione del programma. In un sistema time-sharing i due tempi possono essere diversi. 66 Array multidimensionali array con due o più dimensioni char tris[3][3]; riga 0 1 2 0 colonna 2 1 x o o o x x x o x tris[1][2] 67 Dichiarazione array multidimensionali sintassi (allocazione di memoria) element_type aname [size1] [size2] ... [sizen] sintassi(parametro formale) element_type aname [size1] [size2] ... [sizen] element_type aname [ ] [size2] ... [sizen] esempi double table[NROWS][NCOLS]; void process_matrix(int in[ ][4], /* input matrix */ int out[ ][4], /* output matrix */ int nrows) /* input - number of rows */ 68 Dichiarazione array multidimensionali Viene allocata memoria per l’array aname costituito da size1 size2 . . . sizen celle di memoria. Ogni cella può contenere un dato di tipo element_type. L’accesso agli elementi dell’array è effettuato mediante le variabili indiciate da aname[0][0]...[0] a aname[size1] [size2]...[sizen]. Nella dichiarazione di un array multidimensionale come parametro di una funzione è possibile omettere la prima dimensione (il numero di righe). Come per gli array unidimensionali, il valore effettivamente memorizzato in un parametro formale di tipo array è l’indirizzo del primo elemento dell’argomento attuale. 69 /* Checks whether a tris board is completely filled. */ int filled(const char tris_brd[3][3]) /* input - tris board */ { int r, c, /* row and column subscripts */ ans; /* whether or not board filled */ /* Assumes board is filled until blank is found ans = 1; /* Resets ans to zero if a blank is found for (r = 0; r < 3; ++r) for (c = 0; c < 3; ++c) if (tris_brd[r][c] == ' ') ans = 0; */ */ return (ans); } 70 Inizializzazione di array multidimensionali Per inizializzare un array multidimensionale, occorre raggruppare gli elementi per righe: char tris[3][3] = { {‘ ‘, ‘ ‘, ‘ ‘}, {‘ ‘, ‘ ‘, ‘ ‘}, {‘ ‘, ‘ ‘, ‘ ‘} }; 71 Esempio int celsius[100]; int i; i = 99; printf(“%d”, celsius[i]); printf(“%d”, celsius[i+1]); L’accesso agli elementi dell’array celsius avviene mediante le variabili indiciate celsius[0] ... celsius[99]. La seconda printf effettua un accesso ad un elemento dell’array inesistente (celsius[100]). Di solito non viene segnalato alcun errore a tempo di esecuzione, ma il programma si comporta in modo scorretto. 72 Esempio int a[10]; int i; for (i = 0; i<=10; i++) if (a[i-1] > a[i]) printf(“Array non ordinato.\n”); Errore: accesso ad elementi inesistenti all’inizio del for (a[-1]) e alla fine del for (a[10]). Nell’accesso ad elementi mediante variabile di controllo di cicli controllati da contatore, verificare la correttezza dell’indice per il valore iniziale e il valore finale della variabile di controllo del ciclo. 73 /* * scambia il * elemento e * puntata da */ void min_first(int Esempio minimo elemento di arr con il primo mette il minimo nella locazione minp arr[],int n, int *minp); ... int a[10], min_a; min_first(&a, 10, min_a); Errore: l’argomento a non deve essere preceduto da &; l’argomento min_a deve essere preceduto da &. Chiamata corretta: min_first(a, 10, &min_a); 74 Esempio /* * prende in input da tastiera un numero naturale * e lo memorizza nella locazione puntata da p */ void get_nat(int *p); int a[100]; for (i=0; i<100; i++) get_nat(a[i]); Errore: devo passare l’indirizzo di a[i]. Chiamata corretta: get_nat(&a[i]); 75