• Non ci sono risultati.

Gli array Gli array

N/A
N/A
Protected

Academic year: 2021

Condividi "Gli array Gli array"

Copied!
37
0
0

Testo completo

(1)

Gli array Gli array

Moreno Marzolla

Dipartimento di Informatica—Scienza e Ingegneria (DISI) Università di Bologna https://www.moreno.marzolla.name/

Libro cap. 6

(2)
(3)

Ringraziamenti

prof. Stefano Mizzaro, Università di Udine

http://users.dimi.uniud.it/~stefano.mizzaro/

(4)

Gli array

Scalare

Un “nome” a cui è associato un singolo valore di un determinato tipo

Array

Un “nome” a cui sono associati più valori dello stesso tipo

Ogni valore ha una sua posizione all'interno dell'array

Un array di N elementi ha posizioni etichettate come 0, 1, … N - 1

Il primo elemento dell'array si trova in posizione 0.

x a

x è una variabile scalare di tipo double il cui valore

è 12.34

12.34

12.34 3.14 0.43 3E-12

0.98 0.01 0

1

2

3

4

5

(5)

Esempio

Programma che deve memorizzare 10 valori di temperatura

Uso 10 variabili double temperatura1, temperatura2, ...,

temperatura10??

No, uso un array temperature di 10 elementi di tipo double

Posso accedere ad ogni singolo valore tramite la posizione

temperature

20.5 20.0 19.8 19.4 20.4 21.6 22.0 21.9 21.0 21.1 0

1

2

3

4

5

6

7

8

9

(6)

Dichiarazione e uso

nomeTipo nomeArray[ dimensione ];

Come per le variabili, se non indicato esplicitamente (vedi seguito) il contenuto iniziale degli array è indefinito

Esempi

Per accedere all'elemento si usano le [] e l'indice (posizione) dell'elemento

L'indice deve essere una espressione di tipo int

int giorni[7]; /* giorni[0] … giorni[6] */

float temperature[31]; /* temperature[0] … temperature[30] */

double a[10], b[20]; /* a[0] … a[9], b[0] … b[19] /*

(7)

In C

#include <stdio.h>

int main( void ) {

double temperature[10];

temperature[0] = 20.5;

temperature[1] = 20.0;

temperature[2] = 19.8;

temperature[3] = 19.4;

temperature[4] = 20.4;

/* … */

printf("%f\n", temperature[4]);

/* … */

temperature[5] = temperature[1];

temperature[6] = temperature[5]+1;

temperature[7] = temperature[5+1];

/* … */

return 0;

}

temperature

20.5 20.0 19.8 19.4 20.4 21.6 22.0 21.9 21.0 21.1 0

1

2

3

4

5

6

7

8

9

(8)

Gli esseri umani contano partendo da uno

I computer contano partendo da zero

(9)

Vantaggio degli array

Gestione uniforme

Ad es., per azzerare tutte le temperature…

temperature[0] = 0.0;

temperature[1] = 0.0;

temperature[2] = 0.0;

...

temperature[9] = 0.0;

int i;

for (i=0; i<10; i++) { temperature[i] = 0.0;

}

Anziché fare questo...

...possiamo

fare questo

(10)

Gestione uniforme

Calcolare la media delle temperature

Fatelo con le 10 variabili…

… e poi fatelo per 100…

NB: la dimensione dell'array compare più volte (il letterale 10...); vedremo più avanti come migliorare

double temperature[10];

double somma = 0.0;

int i;

...

for (i = 0; i < 10; i++) {

somma = somma + temperature[i];

}

printf("media=%f\n", somma/10);

(11)

Variable-length arrays

C99 consente di dichiarare array la cui dimensione è contenuta in una variabile

La variabile deve essere dichiarata (quindi visibile) prima della dichiarazione dell'array

Una volta creato l'array, la sua dimensione rimane fissa

/* OK sia in C99 che in ANSI C: a e' un array di 20 int, b e' un array di 10 int; il contenuto iniziale degli array e' indefinito */

int a[20], b[10];

/* OK in C99 (non ammesso in ANSI C): c e' un array di 20 elementi; il suo contenuto iniziale e' indefinito */

int N = 20;

int c[N];

/* OK in C99 (non ammesso in ANSI C): d e' un array di 30 elementi; il suo contenuto iniziale e' indefinito */

const int K = 30;

int d[K];

(12)

Lunghezza di un array

A differenza di altri linguaggi (es., Java), la lunghezza di un array in C non è associata all'array

Non c'è un modo generale per ricavare la lunghezza di un array sapendo il suo nome

In certi casi si può usare l'idioma seguente:

Consiglio di usare un simbolo per memorizzare la lunghezza dell'array

int giorni[] = {31,28,31,30,31,30,31,31,30,31,30,31};

const int ngiorni = sizeof(giorni)/sizeof(giorni[0]); /* OK: ngiorni vale 12 */

(13)

Esempio

Avete scritto un programma per gestire un array di 10 elementi

#include <stdio.h>

int main( void ) {

int v[10], i;

for (i=0; i<10; i++) { v[i] = i*i;

}

/* … */

for (i=0; i<10; i++) {

printf("v[%d]=%d\n", i, v[i]);

}

return 0;

}

(14)

Esempio

...Un bel giorno, qualcuno vi chiede di modificarlo per funzionare con un array di 20 elementi

...ma vi dimenticate di cambiare un numero

#include <stdio.h>

int main( void ) {

int v[20], i;

for (i=0; i<20; i++) { v[i] = i*i;

}

/* … */

for (i=0; i<10; i++) {

printf(“v[%d]=%d\n”, i, v[i]);

}

return 0;

...così dovete andare a caccia di tutti i punti nel

codice in cui usate il vecchio valore, per sostituirlo con il nuovo (che succede se ve ne dimenticate qualcuna?) Ops!

(15)

Soluzione

Memorizzo la lunghezza di un array in un

simbolo N

N non è né una costante né una variabile

Il compilatore vero e proprio non vede N : il simbolo viene sostituito prima della compilazione con la sua definizione

Questa soluzione

funziona sia con ANSI C che con C99

#include <stdio.h>

#define N 10

int main( void ) {

int v[N], i;

for (i=0; i<N; i++) { v[i] = i*i;

}

/* … */

for (i=0; i<N; i++) {

printf("v[%d]=%d\n", i, v[i]);

}

return 0;

}

(16)

Fasi di compilazione

Preprocessore

Compilatore

Linker

GCC

#define N 10 int main( void ) {

int a = N - 1;

int v[N];

return 0;

}

int main( void ) { int a = 10 - 1;

int v[10];

return 0;

}

(17)

Array 17

Inizializzazione

/* OK: calcola la lunghezza automaticamente */

int giorniMese[] = {31,28,31,30,31,30,31,31,30,31,30,31};

/* OK: lunghezza data esplicitamente */

int giorniMese[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

/* OK: pero' giorniMese[2], … giorniMese[11] sono inizializzati a 0 */

int giorniMese[12] = {31,28};

/* OK: pero' il contenuto iniziale dell'array e' indefinito */

int giorniMese[12];

/* NON OK: warning: excess elements in array initializer */

int prova[3] = {10, 30, 20, 20};

/* NON OK: errore: i variable-length arrays non possono essere inzializzati */

const int n = 3; int prova[n] = {10, 20, 30};

..

(18)

Esempi / 1

Dato un array a[N] di int:

Azzerare a[] (assegnare zero a tutti gli elementi di a)

Assegnare 0, 1, 2, … agli elementi di a[]

Incrementare di 1 ogni elemento di a[]

for (i = 0; i < N; i++) { a[i] = 0;

}

for (i = 0; i < N; i++) { a[i] = i;

}

(19)

Esempi / 2

Assegnare 1 agli elementi di a[] di indice dispari e 2 a quelli di indice pari

...oppure...

for (i = 0; i < N; i++) [ if (i % 2 != 0) {

a[i] = 1;

} else {

a[i] = 2;

} }

for (i = 0; i < N; i++) {

a[i] = ( (i % 2 != 0) ? 1 : 2 );

}

(20)

Attenzione...

Attenzione alle soluzioni troppo "astute"

for (i = 0; i < N; i = i+2) { a[i] = 2;

a[i+1] = 1;

}

SBAGLIATO

for (i = 0; i < N-1; i = i+2) { a[i] = 2;

a[i+1] = 1;

}

SBAGLIATO

for (i = 0; i < N; i = i+2) { a[i] = 2;

if ( i+1<N ) { a[i+1] = 1; } }

CORRETTO

ma contorto

(21)

Esercizi

1.[Facile] Dato un array di interi di lunghezza N ≥ 2, determinare i due valori più piccoli

2.Dato un array di interi di lunghezza N ≥ 1, determinare se esiste un valore che compare esattamente 3 volte 3.Dato un array di interi di lunghezza N ≥ 1, determinare

se l'array è ordinato in senso crescente oppure no

(22)

Array bidimensionali (matrici)

Dichiarazione usando doppie parentesi quadre

double t[13][32]

Il primo è il numero di righe, il secondo il numero di colonne

Doppio indice

t[12][2]

Il primo è indice di riga, il secondo di colonna

0 1 2

0 1 2 ... 31

Primo indice

Secondo indice (indice

di colonna)

t[12][2]

(23)

Lavorare su matrici

Data una matrice m[10][30] di int, assegnare 1 a tutti gli elementi

int m[10][30];

int i, j;

for (i = 0; i < 10; i++) {

for (j = 0; j < 30; j++) { m[i][j] = 1;

} }

(24)

Array multidimensionali

Array di array di array di …

Si usa una coppia di [] per ogni dimensione

Es.:

double a[10][100][1000];

a[0][0][0] … a[9][99][999]

Utilità

Temperature di tutte le ore

double t[13][32][24];

... t[12][25][0] ...

(25)

Array multidimensionali

È possibile inizializzare gli array multidimensionali durante la dichiarazione

int x[4]={11,12}; /* OK, {11,12,0,0} */

int y[4]; /* OK, {?,?,?,?} */

int z[] = {3, 5}; /* OK, lunghezza 2 */

int m[3][2]={{11,12},{21,22},{31,32}}; /* OK */

int n[3][2]; /* OK, {{?,?},{?,?},{?,?}} */

int p[][] = {{1,2}, {4,5}}; /* ERRORE */

int q[][2] = {{1,2}, {4,5}}; /* OK */

(26)

Esempi con matrici

Azzerare la riga k-esima di una matrice m[R][C]

#define R 20

#define C 30

int main( void ) {

int m[R][C];

int j, k = ...;

/* … */

for (j = 0; j < C; j++) { m[k][j] = 0;

}

return 0;

}

k

(27)

Esempi con matrici

Azzerare la colonna k-esima di una matrice m[R][C]

k

#define R 20

#define C 30

int main( void ) {

int m[R][C];

int i, k = ...;

/* … */

for (i = 0; i < R; i++) { m[i][k] = 0;

}

return 0;

}

(28)

Esempi con matrici (3/3)

Porre a 1 gli elementi della diagonale principale di una matrice m[N][N], e 0 tutti gli altri

#define N 30

int main( void ) {

int m[N][N];

int i, j;

for (i=0; i<N; i++) {

for (j=0; j<N; j++) { if (i==j) {

m[i][j] = 1;

} else {

m[i][j] = 0;

} }

}

(29)

Esempi con matrici (3/3)

Porre a 1 gli elementi della diagonale principale di una matrice m[N][N], e 0 tutti gli altri

/* soluzione alternativa, usando l'operatore ternario ? (forse meno chiara, ma comunque corretta) */

#define N 30

int main( void ) {

int m[N][N];

int i, j;

for (i=0; i<N; i++) {

for (j=0; j<N; j++) {

m[i][j] = (i==j ? 1 : 0);

} }

return 0;

}

(30)

Esercizio

Realizzare programmi per porre a 1 gli elementi

evidenziati in giallo di matrici m[N][N], 0 tutti gli altri

(31)

Funzioni e parametri di tipo array

In C si possono passare parametri di tipo array alle funzioni senza specificarne la dimensione

Se si modifica il contenuto di un parametro di tipo array viene modificato anche il parametro attuale!

Vedremo il motivo nelle successive lezioni

In C non è consentito che una funzione restituisca un risultato di tipo array

Soluzione: si passa alla funzione un ulteriore parametro di

tipo array, che viene “riempito” con il risultato

(32)

Dichiarare funzioni che accettano parametri di tipo array

void f1( int a[5] ); /* OK, dimensione prefissata */

void f2( int a[] ); /* OK, ma devo sapere per altre vie la dimensione di a */

void f3( int a[], int n );

void f4( int n, int a[n] ); /* OK C99, non ammesso in ANSI C */

void f5( int m[4][3] ); /* OK, dimensioni prefissate */

#define C 40

void f6( int m[][C], int r ); /* OK, passo in r il n. di righe */

void f7(int r, int c, int m[r][c]); /* OK C99, non ammesso in ANSI C */

(33)

Array 33

Passare parametri di tipo array

Quando si invoca una funzione, i parametri di tipo array si passano indicandone il nome

No parentesi quadre ecc.

void f(int a[], int n) {

/* … */

}

#define N 4

int main( void ) {

int v[N] = {1, 2, 3, 4};

f(v, N);

/* … */

return 0;

}

(34)

Esempio

/* iniz-stampa-array.c: inizializza e stampa il contenuto di un array */

#include <stdio.h>

#define N 10

void inizializza(int a[], int n) {

int i;

for (i=0; i<n; i++) { a[i] = i;

} }

void stampa(int a[], int n) {

int i;

for (i=0; i<n; i++) { printf("%d ", a[i]);

}

printf("\n");

}

int main( void ) {

int v[N];

inizializza(v, N);

(35)

E i parametri di tipo matrice?

Passare parametri di tipo matrice è un po' più complicato

Nell'intestazione della funzione occorre

tassativamente indicare il numero di colonne

Il numero di righe può restare non specificato

Se la funzione deve conoscere il numero di righe, è

necessario passare tale informazione mediante un ulteriore

parametro intero, o in qualche altro modo

(36)

/* parametro-matrice.c: dimostrazione dell'uso di una matrice come parametro di una funzione */

#include <stdio.h>

#define R 3

#define C 4

void inizializza(int m[][C], int r) { int i, j, k = 0;

for (i = 0; i < r; i++) {

for (j = 0; j < C; j++) { m[i][j] = k++;

} }

}

void stampa(int m[][C], int r) { int i, j;

for (i = 0; i < r; i++) {

for (j = 0; j < C; j++) { printf("%d ", m[i][j]);

}

printf("\n");

} }

int main( void ) {

int matrice[R][C];

(37)

Quindi, riassumendo

I parametri di tipo predefinito (int, float, double, char) vengono passati per valore

Le modifiche non si riflettono sul parametro attuale

I parametri di tipo array e matrice sono passati “per riferimento”

Modifiche su parametro formale si riflettono sul parametro

attuale

Riferimenti

Documenti correlati

¨  L’espressione a[i] restituisce il valore della variabile con indice i, quindi il tipo di questa espressione è il tipo base dell'array. Accesso agli elementi di

I: il valore di ciascun elemento dello array bidimensionale Pi: il numero degli elementi da inserire non può essere maggiore della cardinalità dell’array. U: l’array

I: il valore di ciascun elemento dello array bidimensionale Pi: il numero degli elementi da inserire non può essere maggiore della cardinalità dell’array. U: l’array

Prima di chiamare la free sull'array chiamarla su ogni

Ci serviamo di un indice j che scorre tutti i caratteri della stringa nome assegnata in input finché non raggiunge il carattere nullo; ognuno di questi caratteri deve essere

● Se gli estremi degli scaglioni e/o le percentuali cambiano, devo cambiare solo l'array e non il programma che fa la ricerca!.. Algoritmi su

 Si dice anche che l'array o vettore è una variabile di tipo derivato, perché costruito a partire da altri tipi.. Gli Array

valori.sort(); // restituisce un array con gli stessi elementi di valori, ma ordinati per valore (modifica anche valori). valori.reverse(); // restituisce un array con gli