Le matrici
Realizzare un programma in linguaggio C che acquisisca da tastiera una matrice di interi 4x4
.
I valori degli elementi devono essere compresi nell'intervallo [-5, 5]
.
I valori non validi eventualmente immessi devono essere scartati e non contribuire al conteggio dei valori inseriti.
La seguente sequenza di valori immessi:
0
10
1
2
3
1
3
2
4
2
3
4
5
-8
3
5
4
0
corrisponderà alla matrice:
0 1 2 3
1 3 2 4
2 3 4 5
3 5 4 0
Suggerimenti
Per rendere il programma pronto a gestire matrici di dimensione diversa da quella specificata, conviene definire le seguenti costanti in forma di macro:
#define NRIG (4)
#define NCOL (4)
e formulare tutto il programma utilizzando opportunamente questi valori.
Se un domani servisse per esempio gestire delle matrici 6x3
(o qualsiasi altra dimensione) basterà modificare queste definizioni per adattare automaticamente l'intero programma alla nuova richiesta.
Nella funzione main
si dichiari una matrice NRIG x NCOL
di interi per ospitare i valori letti (vedi S7.1.1 per la sintassi della dichiarazione).
La lettura dei dati può essere svolta con due cicli for
annidati, i cui contatori vengono usati come indici di riga e colonna (si vedano per esempio i cicli in S9.3).
Per esempio
for (i = 0; i < NRIG; i++) {
for (j = 0; j < NCOL; j++) {
do {
/* legge un numero e e lo memorizza */
mat[i][j] = ....
} while(mat[i][j] > MAX || mat[i][j] < MIN);
}
}
All'interno del ciclo annidato si dovrà ripetere la lettura del valore - con un altro ciclo - fintanto che esso non è incluso nell'intervallo richiesto [-5, 5]
, opportunamente indicati con MIN
e MAX
.
Questo terzo ciclo può essere implementato con il costrutto do-while
(S4.8), in modo da eseguirlo almeno una volta, il quale contiene le istruzioni di lettura fgets
e atoi
(S4.8).
1) Stampa della matrice
Stampare la matrice letta col seguente formato:
[MATRICE]
0 1 2 3
1 3 2 4
2 3 4 5
3 5 4 0
Suggerimenti
Supponendo che i valori memorizzati nella matrice siano di tipo int
, si può definire una funzione dichiarata come segue:
void stampa_matrice(int mat[NRIG][NCOL]);
La stampa dei dati può essere svolta con due cicli for
annidati, i cui contatori vengono usati come indici di riga e colonna, in modo simile all'esempio sopra riportato (si veda anche l'esempio in S9.3).
Si può utilizzare l'istruzione putchar('\n')
per stampare l'andata a capo dopo aver stampato i 4
valori su una riga.
La funzione putchar
è una versione specializzata della putc
presentata in S8.3; la funzione precedente equivale a putc('\n', stdout)
.
2) Media per riga
Calcolare la media di ogni riga della matrice.
Stampare il risultato con il formato seguente (nel caso della matrice di esempio):
[MEDIA_RIGHE]
1.500
2.500
3.500
3.000
Suggerimenti
Un modo intelligente di risolvere questo problema è di definire una funzione dichiarata come segue:
double media_riga(int mat[NRIG][NCOL], int riga);
che calcola la media dei valori della matrice mat
sulla riga riga
.
La funzione media_riga
conterrà un ciclo for
che, tenendo fisso l'indice per la riga pari a riga
, somma i 4
elementi della riga e divide la somma per 4
, restituendo il risultato.
Non dimenticare di inizializzare a 0
la variabile che serve a memorizzare la somma dei valori, altrimenti il calcolo si baserà su un valore iniziale aleatorio.
La funzione media_riga
verrà richiamata da un ciclo for
nella funzione main
per la stampa della media di ciascuna delle quattro righe.
3) Media per colonna
Calcolare la media di ogni colonna della matrice.
Stampare il risultato con il formato seguente (nel caso della matrice di esempio):
[MEDIA_COLONNE]
1.500
3.000
3.000
3.000
Suggerimenti
Un modo intelligente di risolvere questo problema è di definire una funzione dichiarata come segue:
double media_colonna(int mat[NRIG][NCOL], int col);
che calcola la media dei valori della matrice mat
sulla colonna col
.
La funzione media_colonna
conterrà un ciclo for
che, tenendo fisso l'indice per la colonna pari a col
, somma i 4
elementi della colonna e divide la somma per 4
, restituendo il risultato.
Non dimenticare di inizializzare a 0
la variabile che serve a memorizzare la somma dei valori, altrimenti il calcolo si baserà su un valore iniziale aleatorio.
La funzione media_colonna
verrà richiamata da un ciclo for
nella funzione main
per la stampa della media di ciascuna delle quattro colonne.
La logica interna della funzione media_colonna
è simile a quella di media_riga
, solo che il ciclo all'interno di media_colonna
tiene fissa la colonna e ne somma gli elementi, mentre media_riga
tiene fissa la riga.
4) Media di tutti gli elementi
Calcolare la media di tutti gli elementi della matrice.
Stampare il risultato con il formato seguente (nel caso della matrice di esempio):
[MEDIA]
2.625
Suggerimenti
Si definisca una funzione dichiarata come segue:
double media(int mat[NRIG][NCOL]);
Nella funzione media
potranno essere utilizzati due cicli for
annidati per indicizzare tutti gli elementi e sommarne il valore ad una opportuna variable somma
.
Il valore di somma
andrà diviso per 16
per il calcolo della media.
Non dimenticare di inizializzare la variabile somma
a zero, altrimenti il calcolo della media si baserà su un valore iniziale aleatorio.
5) Frequenza dei valori
Stampi a video le frequenze di occorrenza dei valori usando il formato:
[FREQUENZE]
0
0
0
0
0
2
2
3
4
3
2
Nella prima riga si riporti le frequenze dei -5
, nella seconda le frequenze dei -4
, ecc.
Suggerimenti
La soluzione può essere realizzata con una funzione come la seguente:
void frequenze(int mat[NRIG][NCOL], int freq[]);
La funzione frequenze
riceve due parametri: la matrice mat
contenente i numeri di cui calcolare la frequenza, e il vettore delle frequenze.
Un esempio di calcolo delle frequenze è riportato in (S6.8).
Tutti i parametri devono essere dichiarati nel main
che chiama la funzione frequenze
.
Fai attenzione all'inizializzazione dei valori del vettore che conterrà le frequenze, in quanto:
- l'inizializzazione va fatta nel
main
; - come tutte le variabili, un vettore non inizializzato contiene elementi i cui valori sono aleatori;
- l'inizializzazione dei vettori è illustrata in S5.9.2.
La stampa delle frequenze avvenga con un ciclo for
nel main
, dopo aver stampato il marcatore.
La logica per il calcolo delle frequenze è la stessa suggerita nel tutorato relativo ai vettori. La differenza è che ora si dovranno svolgere due cicli per esaminare tutte le righe e le colonne, invece che un solo ciclo che esamina gli elementi del vettore.
6) Rotazione della matrice
Si ruoti la matrice di 90 gradi in senso orario.
Data la matrice d'esempio:
0 1 2 3
1 3 2 4
2 3 4 5
3 5 4 0
la matrice ruotata deve essere:
3 2 1 0
5 3 3 1
4 4 2 2
0 5 4 3
e il programma deve stampare:
[RUOTA]
3 2 1 0
5 3 3 1
4 4 2 2
0 5 4 3
Suggerimenti
Si crei una funzione come la seguente:
void ruota(int output[NRIG][NCOL], const int input[NRIG][NCOL]);
La funzione conterrà gli usuali due cicli for
annidati che, per ciascun valore della matrice input
lo assegnano all'elemento corretto della matrice output
.
Si ricordi che i due argomenti sono degli array, pertanto il passaggio dei parametri avviene per riferimento.
Pertanto, modificando nella funzione ruota
il valore di un elemento di output
, ne risulterà modificato il valore nella variabile passata come argomento.
Non c'è rischio di modificare i valori della matrice input
in quanto l'argomento è dichiarato const
.
NOTA: per la rotazione, il segreto è gestire correttamente gli indici delle matrici!
Se non riesci a trovare la soluzione.... scopri un piccolo aiuto »Verifica automatica
Si utilizzi il tool pvcheck
di verifica automatica per testare il corretto funzionamento del programma (maggiori informazioni circa l'uso di pvcheck
sono disponibili qui).
Il file contenente i test è matrici.test.
Il comando da eseguire per il test è il seguente:
pvcheck -f matrici.test ./a.out
Nella prossima pagina potrai esaminare un esempio di soluzione dell'esercizio.