Vettori (a una dimensione)
Dichiarazione. Prima di essere usato, un vettore deve essere
dichiarato. Per dichiarare che voti è un vettore di interi con 5
componenti si usa l’istruzione di dichiarazione
int voti[5];
Essa fornisce il tipo dati delle componenti (o elementi) del vettore, il
suo nome e il numero delle sue componenti. Altri esempi di
dichiarazioni sono:
A ogni vettore il compilatore riserva memoria sufficiente per
contenere il numero di valori indicati nell’istruzione di dichiarazione.
Quindi, nella ipotesi che ciascun carattere sia memorizzato usando 1
byte e che ciascun numero intero ne usi 2, il vettore codici ha
memoria riservata per 4 caratteri,
il vettore voti ha memoria per 5 numeri in doppia precisione
e prezzi ha memoria per 6 numeri in virgola mobile.
Le singole componenti dei due vettori precedenti sono memorizzate in
modo sequenziale, con la prima componente memorizzata nella
prima locazione riservata, la seconda nella seconda e così via.
Per accedere a una singola componente di un vettore a una
dimensione si indica il nome del vettore e la posizione in esso della
componente.
La posizione della componente è detta subscritto o (valore
dell’)indice. La prima componente ha indice 0, la seconda 1 e la iesima ha indice i-1.
In C il nome del vettore e l’indice sono combinati scrivendo l’indice in
parentesi quadre dopo il nome del vettore.
Così:
Ogni singola componente è detta variabile indicizzata o con subscritto,
dato che per individuarla servono sia il nome della variabile sia un
valore di indice o subscritto.
Sebbene possa sembrare insolito riferirsi alla prima componente con
un indice zero, ciò aumenta la velocità con cui il computer accede
alle componenti del vettore.
Come mostra la figura seguente,
l’indice dice al computer quanti elementi vanno saltati, a partire
dall’inizio del vettore, per raggiungere la componente desiderata.
Le variabili con indice si possono usare in tutti i casi in cui siano valide
le variabili scalari.
Esempi di istruzioni che usano gli elementi del vettore voti sono:
voti[0] = 98;
voti[1] = voti[0] - 1;
voti[2] = 2 * (voti[0] - 6);
L’indice in parentesi non deve essere necessariamente un intero, ma
può essere una qualsiasi espressione che venga valutata a un
intero.
Ad es., se i e j sono variabili intere, sono valide le seguenti
variabili con indici:
voti[i];
voti[2*i];
voti[j-i];
Un vantaggio di usare come indici espressioni intere è che ciò
consente di muoversi sequenzialmente attraverso un vettore con un
ciclo for.
Quindi, non è necessario scrivere un’espressione del tipo:
totale = voti[0]+voti[1]+voti[2]+voti[3]+voti[4]
ma si può sostituirla con il ciclo:
totale = 0;
for (i = 0; i <= 4; ++i);
totale += voti[i];
In esso la variabile i è usata sia come contatore del ciclo, sia come
indice del vettore.
Vediamo come assegnare i valori alle componenti di un vettore a una
dimensione.
Ingresso dei valori. I valori dei singoli elementi di un vettore si
possono assegnare:
• in modo interattivo, tramite la funzione scanf(), oppure
• tramite istruzioni di inizializzazione in un programma.
Esempi di istruzioni d’ingresso interattivo sono:
scanf(“%c”, &codice[0]);
scanf(“%d %lf”, &voti[0], &prezzo[2]);
for (i = 0; i <= 4; i++)
{
printf(“Scrivi un voto: “);
scanf(“%d”, &voti[i]);
}
Il precedente ciclo for richiede all’utente di scrivere 5 voti, e
memorizza il primo in voti[0], il secondo in voti[1] e così via.
Dato che il C non controlla il valore dell’indice usato, se un vettore è
stato dichiarato costituito da 10 elementi e si usa l’indice 12, C non
segnala l’errore in fase di compilazione.
Il programma tenta di accedere all’elemento 12 procedendo oltre il
giusto numero di byte a partire dall’inizio del vettore.
Di solito, ma non sempre, ciò determina un crash del programma.
Se infatti la locazione a cui si fa riferimento contiene come valore un
dato, il programma accederà a esso, dando luogo a errori
particolarmente difficili da trovare quando si userà in un altro punto
del programma la variabile legittimamente assegnata alla locazione
di memoria.
Inizializzazione. Gli elementi di un vettore possono essere inizializzati
all’interno delle loro istruzioni di dichiarazione, come le variabili
scalari, con la differenza che:
i valori di inizializzazione vanno racchiusi
tra parentesi graffe e separati con virgole
Esempi di inizializzazioni di vettori di numeri sono:
int voti[5] = {24, 29, 30, 30, 27};
double larg[6]={10.96, 6.43, 2.58, .86, 5.89, 7.56};
float temp[4] = {98.6, 97.2 99.0, 101.5};
Un vettore di caratteri, può essere inizializzato o indicando i singoli
caratteri, racchiusi tra apici semplici,
char codici[4] = {‘r’, ‘o’, ‘m’, ‘a’};
oppure, in modo equivalente, con una stringa racchiusa tra apici doppi:
char codici[4] = {“roma”};
Se il numero di inizializzatori è minore del numero di elementi dichiarato
nelle parentesi quadre, gli inizializzatori sono applicati a partire
dall’elemento 0 del vettore, e gli altri elementi sono inizializzati a 0.
Non c’è un modo per indicare la ripetizione di un valore di
inizializzazione, o per inizializzare alcuni elementi di un vettore senza
prima avere inizializzato quelli precedenti.
Se nell’istruzione di dichiarazione non sono forniti inizializzatori
specifici, tutti gli elementi del vettore sono posti uguali a 0.
Una caratteristica utile degli inizializzatori è che:
la dimensione di un vettore può essere omessa quando i valori
di inizializzazione sono inseriti nell’istruzione di dichiarazione.
Ad es., la dichiarazione
int litri[] = {16, 12, 10, 14, 11}
riserva spazio sufficiente per 5 elementi.
Uscita dei valori. Per quanto riguarda l’uscita, si possono
visualizzare:
 singoli elementi del vettore, con una chiamata alla funzione
printf(), oppure
 intere sezioni del vettore inserendo una chiamata alla funzione
printf() all’interno di un ciclo for.
Esempi:
printf(“%lf”, prezzo[6]);
visualizza il valore della variabile con indici in doppia precisione
prezzo[6]
for (n = 5; n <= 20; ++n)
printf(“%d %lf”, n, prezzo[n]);
inserisce printf() all’interno di un ciclo for, e visualizza i valori
degli indici e degli elementi dal 5 al 20.
Il programma seguente illustra queste tecniche d’ingresso e uscita
usando un vettore di nome voti, definito per memorizzare 5
numeri interi.
#include <stdio.h>
void main(void)
{
int i, voti[5];
for (i = 0; i <=4; ++i)
{
printf(“Scrivi un voto: “);
scanf(“%d”, &voti[i]);
}
for (i = 0; i <= 4; ++i)
printf(“\nIl voto n° %d è %d”, i, voti[i]);
}
Nel programma vi sono due cicli for:
• il primo percorre l’intero vettore e consente di immettere i suoi singoli
valori;
• il secondo visualizza i valori memorizzati.
Ecco l’uscita prodotta:
Scrivi
Scrivi
Scrivi
Scrivi
Scrivi
Il
Il
Il
Il
Il
voto
voto
voto
voto
voto
un
un
un
un
un
n°
n°
n°
n°
n°
voto:
voto:
voto:
voto:
voto:
0
1
2
3
4
è
è
è
è
è
28
30
29
27
29
28
30
29
27
29
Componente massima. Come altro esempio di uso di un ciclo for
per la scansione di un vettore, troviamo il massimo di 1.000 numeri,
che assegniamo alle componenti di un vettore prezzo.
1. Supponiamo inizialmente che il massimo sia la prima componente
del vettore:
massimo = prezzo[0];
2. Quindi, muovendoci sequenzialmente attraverso il vettore,
confrontiamo tale massimo con ciascuna componente, e se ne
troviamo una con valore maggiore la poniamo come nuovo massimo:
for (i = 1; i <= 999; ++i)
if prezzo[i] > massimo
massimo = prezzo[i];
In questo codice il ciclo for consiste in una sola istruzione if.
La ricerca di un nuovo valore massimo comincia con la componente 1
del vettore e continua fino all’ultima (che nel caso nostro ha indice
999).
Esercizio: somma degli elementi. I valori memorizzati negli elementi
di un vettore possono subire diverse elaborazioni, la più semplice
delle quali è la somma. Scrivere un programma che:
• assegni ciascun voto
a un elemento di un
vettore,
• lo accumuli in un
totale, quindi
• visualizzi i singoli
elementi del vettore e
il totale.
#include <stdio.h>
#define DIM 5
void main(void)
{
int i, voti[DIM], totale = 0;
for (i = 0; i <= 4; ++i)
{
printf("Scrivi un voto: ");
scanf("%d", &voti[i]);
}
printf("\nIl totale dei voti ");
for (i = 0; i < DIM; ++i)
{
printf("%d ", voti[i]);
totale += voti[i];
}
printf("è %d",totale);
}
Esercizio: somma e media. Modificare il programma precedente in
modo che fornisca anche la media dei voti.
#include <stdio.h>
#define DIM 5
void main(void)
{
int i;
float voti[DIM], totale = 0.;
for (i = 0; i <= 4; ++i)
{
printf("Scrivi un voto: ");
scanf("%f", &voti[i]);
}
printf("\nIl totale dei voti ");
for (i = 0; i < DIM; ++i)
{
printf("%3.0f ", voti[i]);
totale += voti[i];
}
printf(“è %4.0f\n",totale);
printf("La media dei voti è %f", totale/DIM);
}
Da vettore a istogramma. Spesso può essere utile rappresentare i
valori delle componenti di un vettore nel formato di un grafico a
barre o istogramma, facendo visualizzare a fianco di ogni valore
una barra composta da altrettanti caratteri ▓ (di codice ASCII
178).
Ad es., si potrebbe volere una rappresentazione di questo tipo:
Le barre possono essere disegnate con un ciclo for nidificato,
all’uscita del quale un carattere \n fa avvenire la stampa del
prossimo valore a riga nuova, come indica il programma seguente.
#include <stdio.h>
#define DIM 10
int main()
{
int n[DIM] = {19, 3, 15, 7, 11, 9, 13, 5, 17, 1};
int i, j;
printf("%s", "Elemento Valore
Istogramma\n");
for (i = 0; i < DIM; i++)
{
printf("%5d %10d
", i, n[i]);
for (j = 1; j <= n[i]; j++)
{
printf("%c", '▓'); /* alt+178 */
}
printf("\n");
}
}
Vettori a due dimensioni (matrici)
Un vettore a due dimensioni rappresenta una tabella o matrice, nella
quale i valori sono organizzati in righe e colonne. Le righe di una
matrice sono sostanzialmente dei vettori a una dimensione.
Dichiarazione. Per dichiarare che val è un vettore di interi a due
dimensioni, corrispondente alla tabella
8
16
9
52
3
15
27
6
14
25
2
10
scriveremo un’istruzione quale:
int val[3][4];
Analogamente, l’istruzione
double prezzi[10][5];
dichiara che la matrice prezzi consiste in 10 righe e 5 colonne di
numeri in doppia precisione, mentre
char codici[6][26];
dichiara che la matrice codici consiste in 6 righe e 26 colonne di
caratteri.
Per individuare ciascun elemento di una matrice, lo si identifica con la
sua posizione in essa. Come mostra la figura, la scrittura
val[1][3]
identifica in modo univoco l’elemento nella riga 1, colonna 3.
Come i vettori a una dimensione, anche le matrci si possono usare
in qualsiasi punto in cui siano valide le variabili scalari.
Esempi di istruzioni che usano gli elementi della matrice val sono:
num = val[2][3];
val[0][0] = 62;
nuovo_num = 4 * (val[1][0] - 5);
Inizializzazione. Come i vettori a una dimensione, anche le matrici
possono essere inizializzate all’interno delle loro istruzioni di
dichiarazione, elencando i valori iniziali entro parentesi {} separate
da virgole.
Ad es., la dichiarazione
int val[3][4] = { {8, 16, 9, 52},
{3, 15, 27, 6},
{14, 25, 2, 10} };
dichiara val come una matrice di interi con 3 righe e 4 colonne, con i
valori iniziali dati nella dichiarazione. Il primo gruppo di parentesi
interne contiene i valori della riga 0 della matrice, il secondo quelli
della riga 1, ecc.
Sebbene le virgole nelle parentsi d’inizializzazione siano necessarie,
le parentesi interne possono essere omesse
dato che l’inizializzazione avviene comunque riga per riga.
Quindi la precedente dichiarazione può essere sostituita da:
int val[3][4] = {8,16,9,52,3,15,27,6,14,25,2,10};
Visualizzazione. Come i vettori a una dimensione, anche le matrici
possono essere visualizzate
• con istruzioni relative ai singoli elementi, oppure
• con dei cicli, sia for sia while.
Il programma seguente visualizza gli elementi di una matrice 3 * 4 con
due cicli for nidificati, controllati quello esterno dalla variabile ri
(che stampa le righe), quello interno dalla variabile co (che stampa
le colonne).
#include <stdio.h>
void main(void)
{
int ri, co, val[3][4]={8,16,9,52,3,15,27,6,14,25,2,10};
printf("Visualizza vettore con ciclo for nidificato");
for (ri = 0; ri < 3; ++ri)
{
printf("\n"); /* stampa ciascuna riga a linea nuova */
for (co = 0; co < 4; ++co)
printf("%2d ", val[ri][co]);
}
}
Ecco l’uscita prodotta:
Visualizza vettore con ciclo for nidficato
8 16
9 52
3 15 27
6
14 25
2 10
Moltiplicazione per uno scalare. Come primo esempio di
operazioni con le matrici, scriviamo un programma che moltiplichi
per 10 ciascuna componente della matrice precedente, quindi
visualizzi i valori calcolati.
#include <stdio.h>
void main(void)
{
int ri, co, val[3][4]={8,16,9,52,3,15,27,6,14,25,2,10};
printf("\nVisualizza gli elementi moltiplicati\n");
for (ri = 0; ri < 3; ++ri)
{
printf("\n");
for (co = 0; co < 4; ++co)
printf("%3d ", val[ri][co]*10);
}
}
Ecco l’uscita prodotta:
Visualizza gli elementi moltiplicati
80 160
90 520
30 150 270
60
140 250
20 100
Esercizio. Sommare tra loro gli elementi della precedente matrice a
3 righe e 4 colonne.
#include <stdio.h>
void main(void)
{
int ri, co, totale=0;
int val[3][4]={8,16,9,52,3,15,27,6,14,25,2,10};
printf("La somma degli elementi della matrice");
for (ri = 0; ri < 3; ++ri)
{
printf("\n");
for (co = 0; co < 4; ++co)
{
totale = totale + val[ri][co];
printf("%2d ", val[ri][co]);
}
}
printf("\nè %d", totale);
}
Tavola pitagorica. Abbiamo già
visto il diagramma di flusso per
stampare la tavola pitagorica.
Possiamo adesso tradurlo nel seguente programma C:
#include <stdio.h>
main()
{
int ri, co, n;
printf("Scrivi l'ordine della tavola pitagorica: ");
scanf("%d", &n);
for (ri = 1; ri <= n; ri++)
{
for (co = 1; co <= n; co++)
printf("%4d", ri*co);
printf("\n");
}
}
Ecco l’uscita prodotta:
Triangolo di Tartaglia. Come è noto, se consideriamo le potenze
successive del binomio (a + b), ossia:
(a
(a
(a
(a
(a
+
+
+
+
+
b)0
b)1
b)2
b)3
b)4
=
=
=
=
=
1
a + b
a2 + 2*a*b + b2
a3 + 3*a2*b + 3*a*b2 + b3
a4 + 4*a3*b + 6*a2*b2 + 4*a*b3 + b4
e scriviamo i soli coefficienti dei vari monomi
otteniamo una tabella nota come “triangolo di Tartaglia”. In essa gli
elementi di ciascuna riga si possono ottenere con il seguente
algoritmo:
 il primo elemento è sempre uguale a “1”;
 ciascun altro elemento si ottiene sommando i due che gli “stanno
sopra” nella riga precedente (ossia: il k-mo elemento di una riga si
ottiene sommando il k-1-mo e il k-mo elemento della riga
precedente).
Per calcolare il triangolo useremo una matrice di ordine N, quindi
calcoleremo dapprima la prima riga, poi le righe successive, quindi
stamperemo l’intera tabella al solito modo.
Il programma completo è il seguente:
Esercizio. Modificare il programma precedente in modo che stampi il
triangolo di Tartaglia nella sua forma più usuale:
A tale scopo è sufficiente modificare la parte del programma che
stampa il triangolo (evidenziata in grigio), facendo stampare un
numero adeguato di spazi vuoti all’inizio di ogni riga e tra un numero
e l’altro.
Ricordiamo che:
 ciascun intero è giustificato a destra nel proprio campo;
 tra un campo numerico e il successivo il C stampa uno spazio vuoto.
Dato che ciascun elemento del triangolo viene stampato in un campo
di 4 caratteri, per ottenere l’allineamento voluto sarà necessario
stampare:
 N-r-1 gruppi di 3 spazi vuoti all’inizio della r-esima riga:
 uno spazio vuoto dopo ciascun campo numerico.
Il programma modificato è pertanto il seguente:
#include <stdio.h>
#define N 10
main()
{
int r, c, TT[N][N], k;
TT[0][0] = 1;
for (c = 1; c < N; c++)
TT[0][c] = 0;
for (r = 1; r < N; r++)
{
TT[r][0] = 1;
for (c = 1; c < N; c++)
TT[r][c] = TT[r-1][c-1] + TT[r-1][c];
}
for (r = 0; r < N; r++)
{
{
for (k = 0; k < 3*(N-r-1); k++)
printf ("%c", '*');
}
for (c = 0; c <= r; c++)
printf("%4d %c", TT[r][c], ' ');
printf("\n");
}
}
Esercizio. Modificare il programma precedente in modo che stampi il
triangolo di Trataglia nella forma seguente:
È sufficiente apportare due semplici modifiche alla sezione di stampa
del programma precedente:
1.invertire l’ordine con cui varia l’indice di riga del ciclo for esterno,
facendolo partire da N-1 e arrivare a 0;
2.spostare il ciclo for interno che stampa gli spazi vuoti dopo il ciclo
for interno che stampa gli elementi della riga generica (con una
leggera modifica del valore finale del suo contatore)
#include <stdio.h>
#define N 10
main()
{
int r, c, TT[N][N], k;
TT[0][0] = 1;
for (c = 1; c < N; c++)
TT[0][c] = 0;
for (r = 1; r < N; r++)
{
TT[r][0] = 1;
for (c = 1; c < N; c++)
TT[r][c] = TT[r-1][c-1] + TT[r-1][c];
}
for (r = N-1; r >= 0; r--)
{
for (c = 0; c <= r; c++)
printf("%4d %c", TT[r][c], ' ');
printf("\n");
for (k = 0; k <= 3*(N-r);
printf ("%c", ' ');
}
}
k++)
Vettori a più di due dimensioni. Sebbene i vettori a più di due
dimensioni non siano usati molto di frequente, il C consente di
dichiarare un numero qualsiasi di dimensioni, semplicemente
elencando il valore massimo di ciascuna dimensione.
Ad es., la dichiarazione
int risposta[4][10][6];
dichiara un vettore a tre dimensioni.
Il primo elemento del vettore si indica
risposta[0][0][0]
e l’ultimo
risposta[3][9][5].
Scarica

Fonda15