Corso di Laboratorio di Informatica Ingegneria Clinica – BCLR
Unità 7
Array
Domenico Daniele Bloisi
Docente
Ing. Domenico Daniele Bloisi, PhD Ricercatore
Dipartimento di Ingegneria Informatica, Automatica e Gestionale “Antonio Ruberti”
Via Ariosto 25
(adiacente Piazza Dante, Manzoni
Tram 3 fermata via Labicana) email: bloisi@dis.uniroma1.it
home page: http://www.dis.uniroma1.it/~bloisi
Ricevimento
In aula, subito dopo le lezioni
Su appuntamento (tramite invio di una email) presso:
Dipartimento di Ingegneria Informatica, Automatica e Gestionale “Antonio Ruberti”,
via Ariosto 25 - II piano, stanza A209
Si invitano gli studenti a controllare regolarmente la bacheca degli avvisi
http://www.dis.uniroma1.it/~bloisi/didattica/labinf1415.html#Avvisi
Orari
Lunedì 12.00 – 13.30
Aula 4, via del Castro Laurenziano 7A
Martedì 14.00 – 17.15
Aula 15, Laboratorio Didattico via Tiburtina 205
Mercoledì 12.00 – 13.30
Aula 4, via via del Castro Laurenziano 7A
Sommario – Unità 7
• Array come collezione di elementi
• Dichiarazione di variabili array
• Creazione di array
• Accesso agli elementi di un array
• Espressioni che rappresentano array
• Passaggio di parametri di tipo array
• Variabili array e puntatori
• Ordinamento degli elementi di un array
• Ricerca tra gli elementi di un array
• Matrici
Array
Un array è
Una collezione di elementi dello stesso tipo
Ogni elemento è indicizzato (cioè identificato) da un numero
Una variabile di tipo array è
un riferimento alla collezione di elementi che costituisce l’array
Array
Per usare un array in C si deve:
1. Dichiarare una variabile di tipo array,
specificandone la dimensione (cioè il numero di elementi dell’array);
2. Accedere mediante la variabile array agli
elementi dell’array, per assegnare o per leggere i loro valori (come se fossero singole variabili).
Array
Dichiarazione di variabili array
Sintassi
tipo nomeArray [n] ; dove
tipo è il tipo degli elementi dell'array a cui si riferisce la variabile che si sta dichiarando
nomeArray è il nome della variabile (riferimento ad) array che si sta dichiarando
n è il numero di elementi dell'array che si sta dichiarando
Semantica
Dichiara una variabile nomeArray che potrà riferirsi ad un array di n elementi di tipo tipo.
Esempio
int a[5]; // a e’ una variabile di // tipo riferimento ad
// array di 5 interi
Cassettiera
typedef int cassetto;
cassetto cassettiera[7];
cassettiera è una variabile di tipo riferimento ad array di 7 cassetti
(cioè variabili di tipo cassetto)
Array e funzione sizeof
La funzione sizeof() consente di avere informazioni sulle dimensioni di un array dichiarato staticamente.
Esempio
int a[5];
printf("dimensione array %d byte\n", sizeof(a));
printf("dimensione array %d elementi\n", sizeof(a)/sizeof(int));
Se un int ha dimensione 4 byte la stampa sarà
dimensione array 20 byte (= 4 byte × 5 elementi)
dimensione array 5 elementi (= 20 byte / 4 byte)
Accesso ai singoli elementi di un array
Sintassi
nomeArray[indice]
dove
nomeArray è il nome della variabile array che contiene un riferimento all'array a cui si vuole accedere
indice è una espressione di tipo int non
negativa che specifica l'indice dell'elemento a cui si vuole accedere.
Semantica
Accede all'elemento di indice indice dell'array nomeArray per leggerlo o modicarlo.
Se l'array nomeArray contiene n elementi, la
valutazione dell'espressione indice deve fornire un numero intero nell'intervallo [0, n-1]
Se ciò non avviene, si ha un comportamento non predicibile, con la possibilità di ottenere un errore in esecuzione.
Esempio
int a[5]; // a e’ una variabile di tipo array di interi
// viene creato un array con 5 elementi di int a[0] = 23; // assegnazione al primo elemento dell’array a[4] = 92; // assegnazione all’ultimo elemento dell’array a[5] = 16; // ??????: l’indice 5 non e’ nell’intervallo [0,4]
Si osservi che dichiarando una variabile di tipo array, viene contestualmente creato l’array a cui essa si riferisce, e
l’array può, quindi, essere direttamente utilizzato.
Importante
Se l’array contiene N elementi (N=5 nell’esempio), gli indici devono essere necessariamente interi
nell’intervallo [0, N-1], altrimenti potrebbe verificarsi un errore in esecuzione.
Nell’esempio precedente, si potrebbe avere un errore durante l’esecuzione dell’istruzione
a[5]=16;
Compilatore C e Array
Mentre esistono dei linguaggi di programmazione che sono in grado di segnalare errori di superamento dei limiti dell’array, il compilatore C, in genere, non aiuta il programmatore.
Errori di questo tipo possono avere effetti poco comprensibili, poichè corrispondono alla
scrittura/lettura di valori che non riguardano l’array!
Compilatore C e Array
#include <stdio.h>
int main() { int a[5];
a[0] = 23;
a[4] = 92;
a[5] = 16;
}
Il compilatore gcc non segnala alcun errore.
Esempio (1/3)
int a[6];
Alloca un array di 6 elementi, cioè 6 locazioni di
memoria consecutive, ciascuna contenente un intero.
6 è la lunghezza dell’array.
In C l’indice degli elementi va sempre da 0 a lunghezza - 1.
Negli standard pre-C99 la lunghezza di un array deve essere costante (nota a tempo di compilazione).
Esempio (2/3)
indice elemento variabile
0 ? a[0]
1 ? a[1]
2 ? a[2]
3 ? a[3]
4 ? a[4]
5 ? a[5]
a[i] denota l’elemento dell’array a di indice i.
Ogni elemento dell’array è una variabile.
int a[6];
Esempio (3/3)
int a[6], b;
a[0] = 15;
b = a[0];
a[1] = a[0] + b;
printf("%d\n", a[0] + a[1]);
Cosa stampa questo frammento di codice?
Creazione array in C99
#include <stdio.h>
int main() {
int a[6], b;
a[0] = 15;
b = a[0];
a[1] = a[0] + b;
printf("b = %d\n", b);
int c[b];
printf("elementi di c = %d\n",
sizeof(c)/sizeof(int));
}
Questa dichiarazione è accettata dal C99
Inizializzazione di array
E’ possibile, in C, scrivere espressioni che denotino array, specificando una lista di espressioni del tipo degli elementi dell’array della forma:
{ espressione_1, espressione_2, ..., espressione_k } Esempio
int v[4] = { 4, 6, 3, 1 };
è equivalente a:
int v[4];
v[0] = 4; v[1] = 6; v[2] = 3; v[3] = 1;
Errori in inizializzazione
Le espressioni che denotano array possono essere usate solo contestualmente alla dichiarazione di un array.
Il seguente esempio produce un errore in compilazione:
int v[4];
v = { 4, 6, 3, 1 }; // ERRORE
Inizializzazione
Se sono presenti meno inizializzazioni del totale degli elementi, gli elementi rimanenti verranno inizializzati a 0 int n[10] = {3}; // azzera i rimanenti 9
// elementi del vettore
float f[5] = {0.0f} // pone i 5 elementi a 0.0 int y[7] = {}; // ERRORE
Esempio
indice elemento variabile
0 3 a[0]
1 0 a[1]
2 0 a[2]
3 0 a[3]
4 0 a[4]
5 0 a[5]
a[i] denota l’elemento dell’array a di indice i.
Ogni elemento dell’array è una variabile.
int a[6] = {3};
Inizializzazione
Se si omette la dimensione dell’array in una
inizializzazione tramite lista di elementi, la lunghezza dell’array sarà la lunghezza di tale lista
Esempio
int n[] = {1, 2, 3};
equivale a
int n[3] = {1, 2, 3};
Assegnazioni tra array
Non si possono effettuare direttamente delle assegnazioni tra array.
int a[3] = {11, 22, 33};
int b[3];
b = a; // ERRORE
Il frammento di codice riportato sopra genera un errore in compilazione
Relazione tra array e puntatori (1/3)
In generale, data una cella, non è possibile sapere cosa contengano le celle di memoria adiacenti ad essa.
L’unico caso in cui è possibile conoscere quali siano le locazioni di memoria successive e cosa
contengano si ha quando vengono utilizzati degli array.
Relazione tra array e puntatori (2/3)
In C il nome di un array è in realtà l’indirizzo dell’elemento di indice 0.
int array[10];
printf("%p %p", array, &array[0]);
array e &array[0] hanno lo stesso valore.
printf("%p %p", array, &array[0]); stampa 2 volte lo stesso indirizzo.
Relazione tra array e puntatori (3/3)
Possiamo far puntare un puntatore al primo elemento di un vettore.
int arr[7];
int *pi;
pi = arr;
L’ultima istruzione è equivalente a pi = &arr[0];
Un array è un puntatore costante e può essere assegnato a una variabile di tipo puntatore.
Creazione di un array con allocazione dinamica della memoria
Invece di far puntare pi ad un vettore allocato attraverso una dichiarazione (quindi creato nello stack), possiamo farlo
puntare a una zona di memoria allocata dinamicamente (creata nello heap):
int *pi, dim;
scanf("%d", &dim);
pi = malloc(dim * sizeof(int));
if(pi != NULL)
pi[dim-1] = 3;
Esercizio
Esercizio 7.1
Scrivere un programma che legga un intero N da tastiera, allochi dinamicamente un array di N interi, legga N interi da tastiera e stampi gli N interi in ordine inverso.
Esempio
Inserire N:
4
Inserire 4 interi:
12 34 56 78 78 56 34 12
Esempio: somma degli elementi di un array di interi
Il seguente frammento di codice calcola la somma dei valori contenuti in un array
int i, somma = 0;
for (i = 0; i < n; i++) somma += v[i];
Nella variabile somma viene memorizzata la somma parziale degli elementi dell’array fino al valore corrente dell’indice.
Si noti il riferimento alla variabile n che contiene la dimensione dell’array.
Passaggio di parametri di tipo array
La funzione sommaValoriArray prende come parametro un array di interi e restituisce la somma dei valori contenuti nell’array
int sommaValoriArray(int v[], int n) { int i, somma = 0;
for (i = 0; i < n; i++) somma += v[i];
return somma;
}
Passaggio di parametri di tipo array
La specifica del parametro formale int v[] sta ad indicare che il tipo del parametro denotato da v è un array di int.
In pratica, alla funzione viene passato il riferimento all’array.
Sarebbe stato possibile specificare il parametro anche come:
int* v
rendendo esplicito l’uso di un riferimento, ma perdendo l’indicazione esplicita che il riferimento è ad un array.
Esempio d’uso
int main() {
const int n = 4;
// creazione array di n elementi int x[n];
// l’elemento con indice i di x contiene i int i;
for (i = 0; i < n; i++) x[i] = i;
// stampa la somma dei primi N numeri printf("%d\n", sommaValoriArray(x,n));
}
Nota
Il passaggio di un array è un passaggio per
indirizzo. Quindi, la funzione può modificare gli elementi dell’array che viene passato come
parametro.
Questo è possibile perchè quando si passa un
array come parametro ad una funzione, in realtà si sta passando l’indirizzo dell’elemento di indice 0 dell'array e non una copia dell’array.
Esempio
E’ spesso utile passare la dimensione dell’array come ulteriore parametro.
void stampa(double arr[], int arr_dim) { int i;
for (i = 0; i < arr_dim; i++)
printf("%d: %f\n", i, arr[i]);
}
int main() {
double d[4] = {1.1, 2.2, 3.3, 4.4};
stampa(d, 4);
return EXIT_SUCCESS;
Esercizi
Esercizio 7.2
Scrivere una funzione
prodottoScalare(double A[], double B[], int n)
che calcoli il prodotto scalare degli array A e B, assumendo che essi abbiano lo stesso numero di elementi pari ad n.
Si ricorda che il prodotto scalare di A per B è ottenuto come somma dei prodotti A[i]*B[i] per ogni i,
0 ≤ i < n, dove n è il numero di elementi dell’array.
Scrivere un programma per verificare il comportamento della funzione.
Esercizi
Esercizio 7.3
Scrivere una funzione
int contaPari(int array[], int n)
che restituisca il numero di elementi pari contenuti nell’array passato come argomento.
Scrivere un programma per verificare il comportamento della funzione contaPari.
Esercizi
Esercizio 7.4
Scrivere una funzione
double max(double A[], int n)
che restituisca il valore massimo contenuto nell’array passato come argomento (che ha dimensione n).
Scrivere un programma per verificare il comportamento della funzione max.