Le matrici - Soluzione

In questo tutorial non verrà presentata la possibile soluzione nella sua interezza, ma soltano le parti interessanti, che dovranno essere opportunamente integrate per fornire la soluzione completa e compilabile. Per ottenere un programma completo e funzionante, si tratta pertanto di scrivere la funzione main che dichiara le variabili necessarie e che chiama opportunamente le funzioni descritte.

Per cominciare, si assume che vengano dichiarate le seguenti macro:

#define MIN    (-5)
#define MAX    (5)

#define NCOL    (4)
#define NRIG    (4)

Le funzioni descritte di seguito dovranno essere oppotunamente richiamate nel main. Ad esse dovranno essere passati gli argomenti corretti. In particolare, una matrice di dimensione NRIG x NCOL può essere dichiarata come segue:

int mat[NRIG][NCOL];

Lettura della matrice

La funzione che stampa una matrice può essere come la seguente:

void leggi_matrice(int mat[NRIG][NCOL])
{
    int i, j;
    char linea[1024];

    for (i = 0; i < NRIG; i++) {
        for (j = 0; j < NCOL; j++) {
            do {
                fgets(linea, sizeof(linea), stdin);
                mat[i][j] = atoi(linea);
            } while(mat[i][j] > MAX || mat[i][j] < MIN);
        }
    }
}

Il funzionamento del programma è il seguente:

  • il ciclo for più esterno usa il contatore i per esaminare tutte le righe della matrice mat
  • per ciascuna riga, il ciclo for più interno esamina i valori di ciascuna colonna usando il contatore j
  • per ciascun elemento, il ciclo do-while continua a ripetere la lettura di un numero fintanto che questo non è compreso nell'intervallo [MIN, MAX]
    • per la lettura si usa la combinazione di funzioni fgets e atoi (vedi S4.1)
    • si noti l'uso dell'operatore || (OR logico, vedi S11.5.2) che permette di verificare che mat[i][j] non sia ne' < MIN ne' > MAX
  • al termine della funzione, il contenuto di mat viene restituito alla funzione chiamante in quanto la matrice è stata passata per riferimento

Stampa della matrice

La funzione che stampa una matrice può essere come la seguente:

void stampa_matrice(int mat[NRIG][NCOL])
{
    int i, j;
    for (i = 0; i < NRIG; i++) {
        for (j = 0; j < NCOL; j++) {
            printf("%d ", mat[i][j]);
        }
        putchar('\n');
    }
}

Il ciclo for più esterno usa il contatore i per esaminare tutte le righe della matrice mat. Per ciascuna riga, il ciclo for più interno esamina i valori di ciascuna colonna usando il contatore j. Viene stampato ad ogni ciclo l'elemento mat[i][j] seguito da uno spazio per separare gli elementi su ciascuna riga. Alla fine di ogni riga, viene stampata una andata a capo con la putchar, che stampa un carattere '\n' sul terminale.

Media per riga

Per il calcolo della media di ciascuna riga si può usare la seguente funzione:

double media_riga(int mat[NRIG][NCOL], int riga)
{
    int i, somma = 0;
    for (i = 0; i < NCOL; i++) {
        somma += mat[riga][i];
    }
    return ((double) somma)/NCOL;
}

La funzione quale calcola la somma degli elementi sulla riga specificata da riga, e restituisce tale somma divisa per il umero di colonne NCOL.

NOTA: in corrispondenza della return avviene il cast (vedi S5.13.3), ovvero la conversione di tipo esplicita, da int a double di somma. Questo cast è indispensabile in quanto altrimenti verrebbe troncata la parte decimale del risultato). In alternativa si sarebbe potuta dichiarare la variabile somma di tipo double per evitare il cast.

Media per colonna

Per il calcolo della media di ciascuna colonna si può usare la seguente funzione:

double media_colonna(int mat[NRIG][NCOL], int col)
{
    int i, somma = 0;
    for (i = 0; i < NRIG; i++) {
        somma += mat[i][col];
    }
    return ((double) somma)/NRIG;
}

La funzione calcola la somma degli elementi sulla colonna specificata da col, e restituisce tale somma divisa per il umero di colonne NRIG.

NOTA: in corrispondenza della return avviene il cast (vedi S5.13.3), ovvero la conversione di tipo esplicita, da int a double di somma. Questo cast è indispensabile in quanto altrimenti verrebbe troncata la parte decimale del risultato). In alternativa si sarebbe potuta dichiarare la variabile somma di tipo double per evitare il cast.

Media di tutti gli elementi

Per il calcolo della media di tutti gli elementi si può usare la seguente funzione:

double media(int mat[NRIG][NCOL])
{
    int i, j, somma = 0;
    for (i = 0; i < NRIG; i++) {
        for (j = 0; j < NCOL; j++)
            somma += mat[i][j];
    }
    return ((double) somma)/(NRIG * NCOL);
}

il cui funzionamento è il seguente:

  • il ciclo for più esterno usa il contatore i per esaminare tutte le righe della matrice mat
  • per ciascuna riga, il ciclo for più interno esamina i valori di ciascuna colonna usando il contatore j
  • ad ogni ciclo l'elemento mat[i][j] viene sommato a somma
  • in corrispondenza della return il valore della media viene calcolato dividendo somma per il numero totale di elementi, ovvero NRIG * NCOL

NOTA: in corrispondenza della return avviene il cast (vedi S5.13.3), ovvero la conversione di tipo esplicita, da int a double di somma. Questo cast è indispensabile in quanto altrimenti verrebbe troncata la parte decimale del risultato). In alternativa si sarebbe potuta dichiarare la variabile somma di tipo double per evitare il cast.

Frequenze

Per il calcolo della frequenze degli elementi si può usare la seguente funzione:

void frequenze(const int mat[NRIG][NCOL], int freq[])
{
    int i, j;
    for (i = 0; i < NRIG; i++) {
        for (j = 0; j < NCOL; j++) {
            freq[mat[i][j] - MIN]++;
        }
    }
}

Il funzionamento è il seguente:

  • il ciclo for più esterno usa il contatore i per esaminare tutte le righe della matrice mat
  • per ciascuna riga, il ciclo for più interno esamina i valori di ciascuna colonna usando il contatore j
  • ad ogni ciclo l'elemento mat[i][j] viene usato come indice nel vettore freq per conteggiare il numero di occorrenze di tale valoer (la sua frequenza)
  • il dato restituito dalla funzione è il contenuto del vettore freq, il quale è stato passato per riferimento

ATTENZIONE: il valore di MIN deve essere dichiarato come il minimo valore possibile per i numeri nella matrice. Per esempio in questo modo (come mostrato all'inizio del tutorial):

#define MIN   (-5)

Rotazione della matrice

Per il calcolo della frequenze degli elementi si può usare la seguente funzione:

void ruota(int output[NRIG][NCOL], const int input[NRIG][NCOL])
{
    int i, j;
    for (i = 0; i < NRIG; i++) {
        for (j = 0; j < NCOL; j++) {
            output[j][NRIG - i - 1] = input[i][j];
        }
    }
}

Il funzionamento è il seguente:

  • il ciclo for più esterno usa il contatore i per esaminare tutte le righe della matrice input
  • per ciascuna riga, il ciclo for più interno esamina i valori di ciascuna colonna usando il contatore j
  • ad ogni ciclo l'elemento input[i][j] viene assegnato all'elemento output[j][NRIG - i - 1]
  • il dato restituito dalla funzione è il contenuto della matrice output, la quale è stata passata per riferimento

NOTA: per la stampa della matrice usata per passare l'argomento output alla funzione, si può usare la funzione stampa_matrice definita più sopra.

Hands-on

prova-tu Il calcolo della media per riga (o per colonna) e quello della media totale hanno molto in comune: per calcolare la media della riga i-esima bisogna sommare i numeri sulla riga, prima di dividere per il numero di elementi, mentre la media totale può essere vista come la somma delle somme di tutte le righe, che poi viene divisa per il numero totale di elementi della matrice.

Prova quindi a ristrutturare il programma creando una funzione che si limita a calcolare la somma dei valori su una riga (invece che direttamente la media). La funzione che restituisce la somma della riga il cui indice è riga può essere dichiarata come segue:

double somma_riga(int mat[NRIG][NCOL], int riga);

Questa stessa funzione può essere chiamata nel main per calcolare la somma delle righe, e ottenere la media dopo aver diviso (sempre nel main) per il numero di elementi.

Può essere anche chiamata per calcolare la somma di tutte le righe, da dividere poi per il numero totale di elementi della matrice per calcolare la media totale.

In questo modo, si realizza una unica funzione per la soluzione di due quesiti.