Array e Matrici
Problema
Si vuole un programma che chieda 10 numeri all'utente e li visualizzi in ordine inverso.
Si vuole un programma che chieda 10 numeri all'utente e li ordini dal piu' piccolo al piu' grande, per poi stamparli a video.
E' molto scomodo e poco pratico fare uso di 10 variabili separate. E' necessario un contenitore diverso, in grado di contenere N variabili dello stesso tipo.
Introduzione
Variabili vettoriali: contengono più valori dello stesso tipo, detti elementi.
Tutti gli elementi hanno lo stesso nome, ma sono contraddistinti da un numero, detto indice indicato tra parentesi quadre:
a[1] a[2] a[3] a[4]
in termini matematici questo si scrive:
\begin{equation} a_{1} \qquad a_{2} \qquad a_{3} \qquad a_{4} \end{equation}
Se il tipo è di base (come char, int, long, double, etc.), tutti gli elementi del vettore sono variabili scalari di quel tipo
Definizione
Definizione (alloca tutta la memoria per tutti gli elementi):
tipo nome[num_elementi];
La dimensione del vettore deve essere una costante intera positiva
Esempio
int vett[10];
Il numero di elementi deve essere una costante intera positiva (non una const) nota a compile-time
Di norma la costante viene gestita con una #define
Accesso agli elementi
Si accede ai singoli elementi indicando il nome del vettore seguito dall'indice (posizione) dell'elemento tra parentesi quadre.
La posizione puo' essere espressa con una costante, una variabile o con una espressione
vett[2] vett[i] vett[i+2]
Il primo elemento ha indice 0
L'ultimo elemento di un vettore di N elementi ha indice N-1,
quindi nel nostro esempio sara' vett[9]
Uso degli elementi
Dato che gli elementi di un vettore sono equivalenti ad una
variabile del tipo indicato nella definizione
(nel nostro esempio il tipo e' int)
un elemento può essere utlizzato in tutti i contesti in cui
si può usare un valore di quel tipo
1: int vett[10]; 2: int x; 3: 4: scanf ("%d", &vett[0]); 5: 6: x = vett[0] * 5;
Layout in memoria
Gli elementi del vettore sono allocati in locazioni di memoria successivi e contigui
Il nome di un vettore, per il compilatore, in realtà equivale all'indirizzo in memoria del primo elemento del vettore.
Non è quindi una variabile, quindi non gli si può assegnare un valore.
Non possiamo quindi copiare un vettore con un assegnamento.
Attraversare un vettore
E' possibile attraversare tutto un vettore con un ciclo for
1: #define N 10 2: 3: int vett[N]; 4: int i; 5: 6: /* riempie il vettore con valori inseriti dall'utente */ 7: for(i = 0; i < N; i++) { 8: scanf("%d", &vett[i]); 9: }
Si sfora il vettore quando si cerca di accedere ad elementi la cui posizione non è valida, ovvero se la posizione è oltre i limiti del vettore.
Questo errore viene chiamato buffer overflow ed è una vulnerabilità di sicurezza.
1: int vett[4]; 2: int i; 3: 4: for (i = 0; i <= N; i++) { 5: printf("%d", vett[i]); 6: }
Inizializzazione di vettore
Si inizializza un vettore con una lista di valori racchiuse tra parentesi graffe
int vett[4] = {12, 42, 3, 100};
Non e' possibile inserire un numero di valori maggiore della lunghezza del vettore.
Il compilatore ce lo segnalerà con un warning.
Se non inizializziamo il contenuto di un vettore i valori in esso contenuti non sono noti (può esserci qualsiasi valore, non è detto che siano zero).
Se la lista invece contiene meno valori della dimensione del vettore verranno inizializzati solo quelli indicati, mentre i restanti verranno inizializzati a zero.
int v[4] = {6, 2};
Il vettore conterra' 6, 2, 0, 0
Se invece indichiamo
int v[100] = {0};
Il vettore conterra' solo zeri
Passaggio vettori a funzione
Per passare un vettore come argomento, si indica il suo nome senza parentesi
x = media(vettore);
Il parametro formale corrispondente definirà un vettore dello stesso tipo (in genere senza dimensione in quanto ininfluente)
float media(float v[]);
La funzione deve conoscere in qualche modo la dimensione del vettore. Abbiamo piu' possibilita':
- viene passato come argomento
float media(int v[], int lung);
- è noto a priori (es. una #define) questa soluzione rende meno flessibile il codice da noi scritto
Il codice all'interno della funzione, al contrario di quanto avviene con le "normali" variabili, modifica in modo permanente il contenuto dell'array.
Se quindi inseriamo dei valori all'interno dell'array durante l'esecuzione di una funzione, il resto del programma potra' accedere ed utilizzare tali valori.
void carica_array(int valori[], int dim) { for (i = 0; i < dim; i++) { printf("inserisci il valore %d: ", i + 1); scanf("%d", &valori[i]); } } int main() { int v[10]; carica_array(v, 10); printf("%d %d\n", v[0], v[1]); /* la printf stampera' i primi due valori inseriti dall'utente nella funzione */ return 0; }
Esercizi
Es1
Scrivere una funzione C che riceve come parametro un array di double e la sua dimensione e restituisce la media degli elementi presenti nell'array.
Es2
Scrivere una funzione C che riceve come parametro un array di interi, la sua dimensione e due indici h e k e restituisce la somma degli elementi dell’array memorizzati nelle posizioni da h a k
Es3
Scrivere una funzione C che riceve come parametro un array di interi e la sua dimensione e restituisce 1 se tutti gli elementi dell'array sono diversi tra loro
Es4
Scrivi una funzione trova_divisori(int n) che riceva un numero n intero minore di 10000 ed inserisca in un vettore tutti i divisori del numero inserito dall'utente. La funzione chiama a sua volta la funzione stampa_vettore() per visualizzare l'elenco dei divisori trovati.
Es5
Scrivere un programma che riempia un array con N numeri interi e sia in grado di determinare se in tutte le posizioni pari dell’array è memorizzato un numero pari.
Es6
Scrivere un programma che riempia un array da 10 elementi di valori casuali compresi tra 1 e 10. Il programma deve poi stampare su di un'unica riga tutti gli elementi dell'array, Se la somma dei numeri supera 50 il programma dovrà anche contare quanti numeri dell'array sono maggiori di 6 e stamparlo a video. Se la somma dei numeri invece è minore di 50 il programma dovrà contare quanti numeri dell'array sono minori di 4 e stamparlo a video.
Esempio: 1 10 5 8 4 9 7 5 2 3 Numeri maggiori di 6: 4
1 2 5 8 4 9 7 5 2 4
Numeri minori di 4: 3
Es7
Scrivere un programma C che legga dall'utente un array di numeri interi e stampi VERO se il primo valore dell'array e' duplicato
[10, 20, 30, 60, 42, 1200, 10] stampa VERO
Es8
Scrivere una funzione C che legga N numeri, li memorizzi in un vettore, e costruisca poi un secondo vettore contenente i valori del primo in ordine inverso Per esempio:
– valori dell’array: 15, 23, 35, 46, 51, 68, 12, 72;
– valori secondo array: 72, 12, 68, 51, 46, 35, 23, 15
Matrici
Altri esercizi
Es1
Scrivere un programma composto da due funzioni:
- la funzione leggi_array() che riempia un array di 8 numeri interi con valori inseriti dall'utente,
- scrivere una funzione somma() che calcoli la somma di quelli negativi ed inserisca zero al loro posto.
Es2
Creare un array di interi con 10 posti, inserire zeri in tutte le celle; leggere in che posizione inserire un 1 e inserirlo nella corretta posizione dell’array; scandire l’array una cella alla volta fermandosi quando si trova l’uno, dire in che cella è stato trovato.
Es3
Scrivere una funzione che, dato un array di 8 interi, e due numeri inf e pos calcoli e stampi a video quanti valori nell’array sono compresi tra questi.
Es array: 1 3 4 5 6 7 10 100 se inf = 2 sup = 8
il numero calcolato e' 5 in quanto i valori 3, 4, 5, 6, 7 sono compresi nell'intervallo
Es4
Scrivere una funzione che, dato un array di 10 interi, sia in grado di determinare se i valori memorizzati nell’array sono memorizzati in ordine crescente. 1, 2, 3, 4, 10, 50, 70, 100 e' in ordine crescente
1, 2, 4, 5, 3, 10, 20, 30, 4 non e' memorizzato in ordine crescente
Es5
Scrivere una funzione che, dato un array di 10 interi e stampi a video solo i numeri che appaiono nell’array una volta soltanto. Ad esempio se l’array contiene 1, 2, 3, 1, 2, 4 il programma stamperà 3, 4

