Link Search Menu Expand Document

Malloc - Esercizi

Table of contents
  1. Esercizi
    1. Array e Matrici numerici
      1. Memorizzazione sequenza numeri di lunghezza casuale 1
      2. Memorizzazione sequenza numeri di lunghezza casuale 2
      3. Input sequenza numeri in unica riga
      4. Definizione Vettore
      5. Memorizzazione sequenza numeri di lunghezza casuale 1 - col vettore
      6. Memorizzazione sequenza numeri di lunghezza casuale 2 - col vettore
      7. Input sequenza numeri in unica riga - col vettore
      8. Genera matrice dinamica random
      9. Lettura matrice da file
      10. Lettura matrice da file e ordinamenti
      11. Voti studenti
    2. Array e Matrici di Stringhe
      1. Lettura lista stringhe da file e ordinamento
      2. Matrice di stringhe e ordinamenti

Esercizi

Array e Matrici numerici

Memorizzazione sequenza numeri di lunghezza casuale 1

Riempi un array di numeri casuali minori di 100, fermati quando estrai 0 (non aggiungere lo 0)

Soluzione
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    int i, n, cap, numero;
    int *a; // invece di a[]

    srand(time(NULL));

    // qui alloco la memoria per a
    cap = 10;
    a = malloc(cap * sizeof(int));
    // questo mi serve per controllare se il computer riesce ad allocare
    // memoria, se non ci riesce blocco tutto
    if (a == NULL) {
        printf("Non riesco ad allocare abbastanza memoria!");
        return 1;
    }

    // conto quanti numeri estraggo e vado avanti per sempre (poi userò un break
    // quando estraggo 0)
    for (i = 0; 1; i++) {

        // estraggo un numero
        numero = rand() % 100;
        // printf("%d ", numero);

        // se è 0 esco
        if (numero == 0) {
            break;
        }

        // qui mi chiedo se ho già riempito tutto a e non ho più spazio,
        // in tal caso devo ingrandire a
        if (i >= cap) {
            a = realloc(a, cap * sizeof(int) * 2);
            if (a == NULL) {
                printf("Non riesco ad allocare abbastanza memoria!");
                return 1;
            }
            cap *= 2;
        }

        // finalmente posso aggungere numero ad a
        a[i] = numero;
    }
    // mi devo segnare quanti numeri ho estratto
    n = i;

    printf("\n");

    // ora stampo tutto a
    for (i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }
    free(a);
}

Memorizzazione sequenza numeri di lunghezza casuale 2

Genera e memorizza una sequenza di numeri casuali. La sequenza deve terminare quando la media dei numeri è 50 +- 0.01

Soluzione
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <malloc.h>

int main() {
    int num, *a, cap, n;
    float media, somma;

    srand(time(NULL));

    cap = 2;
    n = 0;
    a = malloc(cap * sizeof(int));
    if (a == NULL) {
        printf("Non riesco ad allocare abbastanza memoria!");
        return 1;
    }

    somma = 0;
    while (1) {
        num = rand() % 99 + 1;
        if (n >= cap) {
            cap *= 2;
            a = realloc(a, cap * sizeof(int));
            if (a == NULL) {
                printf("Non riesco ad allocare abbastanza memoria!");
                return 1;
            }
        }
        a[n++] = num;

        somma += num;
        media = somma / n;
        printf("%2d - %5.2f\n", a[n-1], media);
        if (media >= 49.99 && media <= 50.01) {
            break;
        }
    }
}

Input sequenza numeri in unica riga

Chiedi all’utente di inserire in un’unica riga una serie di numeri interi. il tuo programma deve leggere questi numeri e metterli in un array che sia grande esattamente come il numero di numeri inseriti. stampa poi l’array.

Soluzione 1
#include <stdio.h>
#include <string.h>
#include <malloc.h>

int main() {
    char riga[1000], *token;
    int *a, n, i;

    printf("Scrivi una sequenza di numeri interi in una sola riga separati da spazi:\n > ");
    scanf("%[^\n]", riga);

    token = strtok(riga, " ");
    for (n = 0; token != NULL; n++) {
        if (n == 0) {
            a = malloc(sizeof(int));
        }
        else {
            a = realloc(a, (n+1)*sizeof(int));
        }
        if (a == NULL) {
            printf("Non sono riuscito ad allocare abbastanza memoria!\n");
            return 1;
        }
        // printf("%s - ", token);
        sscanf(token, "%d", &a[n]);
        token = strtok(NULL, " ");
    }

    for (i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }
}
Soluzione 2
#include <stdio.h>
#include <string.h>
#include <malloc.h>

int main() {
    char riga[1000], copia[1000], *token;
    int *a, n, i;

    printf("Scrivi una sequenza di numeri interi in una sola riga separati da spazi:\n > ");
    scanf("%[^\n]", riga);
    strcpy(copia, riga);

    token = strtok(copia, " ");
    for (n = 0; token != NULL; n++) {
        token = strtok(NULL, " ");
    }

    a = malloc(n*sizeof(int));
    if (a == NULL) {
        printf("Non sono riuscito ad allocare abbastanza memoria!\n");
        return 1;
    }

    token = strtok(riga, " ");
    for (i = 0; token != NULL && i < n; i++) {
        sscanf(token, "%d", &a[i]);
        token = strtok(NULL, " ");
    }

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

Definizione Vettore

Definisci una struttura che chiamerai VettoreInt. Questa struttura deve contenere un’array dinamico di interi e i relativi valori di e capacità (quanti numeri può contenere) e dimensione (quanti elementi sono effettivamente contenuti). Implementa poi le seguenti funzioni:

  • funzione inizializza per preparare il vettore all’utilizzo allocando la memoria e settando i valori iniziali di dimensione e capacità;
  • funzione push_back per aggiungere un nuovo numero alla fine del vettore
  • funzione pop per eliminare un numero da una determinata posizione del vettore
Soluzione
#include <stdio.h>
#include <malloc.h>

typedef struct {
    int *data;
    int n, cap;
} VettoreInt;

int inizializza(VettoreInt *v) {
    v->n = 0; //(*v).
    v->cap = 0;
    v->data = malloc(sizeof(int) * 4);
    if(v->data == NULL){
        printf("Memoria esaurita\n");
        return 1;
    }
    v->cap = 4;
    return 0;
}

int push_back(VettoreInt *v, int dato) {
    if (v->n >= v->cap) {
        v->data = realloc(v->data, sizeof(int) * v->cap * 2);
        if(v->data == NULL){
            printf("Memoria esaurita\n");
            return 1;
        }
        v->cap *= 2;
    }
    v->data[v->n++] = dato;
    // che equivale a:
    // v->data[v->n] = dato;
    // n += 1;

    // printf("%d", v->n);
    return 0;
}

int pop(VettoreInt *v, int pos) {
    int i;
    if (pos < 0 || pos >= v->n) {
        printf("Posizione indicata per il pop non esistente\n");
        return 1;
    }
    for (i = pos; i < v->n-1; i++) {
        v->data[i] = v->data[i+1];
    }
    v->n--;
    return 0;
} 

Memorizzazione sequenza numeri di lunghezza casuale 1 - col vettore

Dopo aver definito una struttura VettoreInt e le funzioni per usarla come vettore, dichiara e riempi un VettoreInt di numeri casuali minori di 100. Fermati quando estrai 0 (non aggiungere lo 0)

Soluzione
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "1-04-vettore.c" // vedi esercizio sulla definizione di VettoreInt

int main() {
    int i, numero;
    VettoreInt v;

    srand(time(NULL));

    inizializza(&v);

    numero = rand() % 100;
    while (numero != 0) {
        push_back(&v, numero);
        numero = rand() % 100;
    }

    // ora stampo tutto a
    for (i = 0; i < v.n; i++) {
        printf("%d ", v.data[i]);
    }
}

Memorizzazione sequenza numeri di lunghezza casuale 2 - col vettore

Dopo aver definito una struttura VettoreInt e le funzioni per usarla come vettore, genera una sequenza di numeri casuali e salvali in memoria. La sequenza deve terminare quando la media dei numeri è 50 +- 0.01

Soluzione
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <malloc.h>
#include "1-04-vettore.c"

int main() {
    int num, i;
    float media, somma;
    VettoreInt v;

    srand(time(NULL));
    inizializza(&v);

    somma = 0;
    for (i = 0; 1; i++) {
        num = rand() % 99 + 1;
        push_back(&v, num);

        somma += num;
        media = somma / v.n;
        printf("%2d - %5.2f\n", v.data[i], media);
        if (media >= 49.99 && media <= 50.01) {
            break;
        }
    }
}

Input sequenza numeri in unica riga - col vettore

Dopo aver definito una struttura VettoreInt e le funzioni per usarla come vettore, chiedi all’utente di inserire in un’unica riga una serie di numeri interi. il tuo programma deve leggere questi numeri e metterli in un vettore. Stampali infine al contrario.

Soluzione
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "1-04-vettore.c"

int main() {
    char riga[1000], *token;
    VettoreInt v;
    int i, num;

    inizializza(&v);

    printf("Scrivi una sequenza di numeri interi in una sola riga separati da spazi:\n > ");
    scanf("%[^\n]", riga);

    token = strtok(riga, " ");
    for (i = 0; token != NULL; i++) {
        sscanf(token, "%d", &num);
        push_back(&v, num);
        token = strtok(NULL, " ");
    }

    for (i = v.n-1; i >= 0; i--) {
        printf("%d ", v.data[i]);
    }
}

Genera matrice dinamica random

Genera una matrice di numeri casuali di massimo due cifre. Anche la dimensione della matrice deve essere casuale: il numero di righe e di colonne deve essere compreso tra 2 e 10. Ordina poi separatamente ogni riga in ordine crescente.

Leggi i numeri contenuti nel file di input e inseriscili in una matrice dinamica. Dai per scontato che ogni riga contenga la stessa quantità di numeri.

Soluzione
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int cmpfunc (const void * a, const void * b) {
   return ( *(int*)a - *(int*)b );
}

int main() {
    int i, j;
    int N, M;
    int **mat;

    srand(time(NULL));

    N = rand() % (10-2+1) + 2;
    M = rand() % (10-2+1) + 2;
    mat = malloc(N * sizeof(int*));
    if (mat == NULL) {
        printf("Memoria insufficiente.");
        return 1;
    }
    for (i = 0; i < N; i++) {
        mat[i] = malloc(M * sizeof(int));
        if (mat[i] == NULL) {
            printf("Memoria insufficiente.");
            return 1;
        }
        for (j = 0; j < M; j++) {
            mat[i][j] = rand() % 100;
        }
    }

    // stampo separatamente (potevo farlo prima)
    for (i = 0; i < N; i++) {
        qsort(mat[i], M, sizeof(int), cmpfunc);
        for (j = 0; j < M; j++) {
            printf("%2d ", mat[i][j]);
        }
        printf("\n");
    }
}

Lettura matrice da file

Leggi i numeri contenuti nel file di input e inseriscili in una matrice dinamica. Dai per scontato che ogni riga contenga la stessa quantità di numeri.

File di input
 53 15 43 42 24 22 10 82 22  6 68 46 90 60 70  2 14 36 39 53  9 44 38 36 38 45 75 42 98 67
 41 50 86 79 88 64 17 51 68 25  3 84 93 65 99 67 36 70 43 58 42  7 69 68  0 94 83 63 23 74
 63  1 40 15 84 73 19 91 45 67 91 49 91 11 33 20 13 22 34 50 83 82 42 37 38 31  3 22 35  9
  9 49 34 92 44 80 94 21 94 35 90 47 45 95 30 82 28 89 25  7 49 42 69  4 51 77 13 73 85 68
 74 67  7 82  2 64 31  5 69 88 39 15 92 30 36 87 35 70 15 17 85 25 83 62  7 97 42 97 77 31
 96 68 88 34 52 55  9 74 94 65  0 53 45 85 16 12 62 69 98 61 96 56  1 48 89 81  9 76 21 34
 43 32  6 10 35 17 79 18 59 37 78 58 56 72 67 67 50 58 30 40 84 18 72 26  4 41 68 88 32 38
 93 95 74  4 98 33 22 68 90 60 81 65 73 34 12 82 27 22  5 87 63 49 33 82 11 82 83 59 66 27
 36 89 98 94 63 64 72 66 55 52 52 73 23 31 21 29 17 57 80 46 50 19 39 36 24  7 14 86 17 90
 53 62 56 15  5 45 58 62 39 89 18 12 97 17 96 34  8  1 58 92 10 39 80 63 77 89 42 24 11 32
 11 83 40  8 37 12 16 65 62 41  1 70 68 64 89 92 29 38 44 25  0 88  5 69 44 93 17 88 50 41
  0 53 25 13 22  3 94 54 33 42  8  2  1 61 37 76 60 29 13 32 80 64 47 91 13 43 18 80 79 92
 49 79 11 85 10 52 81 33 84 27 90 32 11 47 35 69 96 25 70  1 61 35 19 99 42 28 86 34 33 17
 31 55 15 37  6 67 75 33  8 43 74 63 85 30 52 35 47 55 90 98 83 80 76 59 15 34 38  0 72 58
 77 30 61 11 63 59 79 41 51 14 83 61  1 36 85 34 30 55 98 31 74 60 59 78 55 80 35 57 26 89
 19 27 31 38  1 17 82 65 24 17 31 54 62 35 45  0 85 42 38 21 26 97 73 21 23  7 82 35 95 43
  7 89  8 60 31 53 36 49 39 24  0 12 58 66 21 68 25 54 83 59 91 83 92 37 23  7  1 50 32 19
 27 22 20 36 49 79 40 88 96  2 35 12 63 10 41 64 48 13 69 43  6 89 94  9  0 58 63 82 51 92
 38 61 79 72 14 80 56 74  7 10 94 58 85 19 73 99 71 55 51 46 79 18 82 75 47 69 43 86 78 56
 27 26 91 12 15 30 76 47  3 74 43 84 31 87  6 79 50  2 69 39 18 27 28 47 39 31  1 25 87 31
 23 23 87 41 40 88 48 16  3 77 68 75 13  4 49 10 25 39 82 80 79 45 17 72 67 42 33 71 37  1
 54 94 94 83 17 68 88 65  4 37 63 52 57 13  9 92 78 67 43 87 25 66  0 32 69 13 86 24 56 16
 54 15 14 22 97 14 71 38 64 84 96 55 99  2 80 55 42 64 92 21 68 60 63 90 89 17 76  5 13 28
 65 86 81 81 17 25 42 42 99 86 55 76 49 16 96 99  8 10 85 62 53 54 15 37 49 56 61 82 19 21
 21 99 82 73 34 75 98 89 13  2 23 17 71  1 37 21 45 93 80 54 33 60  0 32  5 43 65  6 57  1
Soluzione
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define K 1000

int main() {
    FILE *fp;
    int i, j;
    // le maiuscole indicano la capacità della matrice, le minuscole  la
    // quantità di valori effettivamente contenuti
    int N, M, n, m;
    int **mat;
    char riga[K];
    char *token;

    fp = fopen("1-09-leggi-matrice-input.txt", "r");
    if (fp == NULL) {
        printf("File non trovato\n");
        return 1;
    }

    N = 2;
    M = 2;
    // qui alloco un array dinamico di puntatori, ognuno a sua volta è un
    // array dinamico. Per ora ogni puntatore non punta a nulla.
    mat = malloc(N * sizeof(int *));
    n = 0;
    m = 0;
    for (i = 0; !feof(fp); i++) {
        if (i >= N) {
            N *= 2;
            // aggiungo puntatori cioè nuove righe
            mat = realloc(mat, N * sizeof(int *));
        }
        // è qui che alloco memoria per la riga i-esima (puntata dal puntatore
        // i-esimo)
        mat[i] = malloc(M * sizeof(int));
        fgets(riga, K, fp);
        token = strtok(riga, " ");
        for (j = 0; token != NULL; j++) {
            if (j >= M) {
                M *= 2;
                mat[i] = realloc(mat[i], M * sizeof(int));
                // qui va considerato che le righe devo essere tutte lunghe
                // uguali se no bisognerebbe fare una cosa più complicata.
                // Qui la realloc viene fatta solo riempiendo la prima riga.
            }
            sscanf(token, "%d", &mat[i][j]);
            token = strtok(NULL, " ");

            printf("%3d", mat[i][j]);
        }
        printf("\n");
    }
    n = i;
    m = j;
}

Lettura matrice da file e ordinamenti

Leggi i numeri contenuti nel file di input e inseriscili in una matrice dinamica. Dai per scontato che ogni riga contenga la stessa quantità di numeri. Dopo aver letto la matrice ordina ogni riga in ordine crescente. Ordina poi tra loro le righe in modo che siano ordnate in ordine crescente secondo il primo numero della riga.

File di input
 53 15 43 42 24 22 10 82 22  6 68 46 90 60 70  2 14 36 39 53  9 44 38 36 38 45 75 42 98 67
 41 50 86 79 88 64 17 51 68 25  3 84 93 65 99 67 36 70 43 58 42  7 69 68  0 94 83 63 23 74
 63  1 40 15 84 73 19 91 45 67 91 49 91 11 33 20 13 22 34 50 83 82 42 37 38 31  3 22 35  9
  9 49 34 92 44 80 94 21 94 35 90 47 45 95 30 82 28 89 25  7 49 42 69  4 51 77 13 73 85 68
 74 67  7 82  2 64 31  5 69 88 39 15 92 30 36 87 35 70 15 17 85 25 83 62  7 97 42 97 77 31
 96 68 88 34 52 55  9 74 94 65  0 53 45 85 16 12 62 69 98 61 96 56  1 48 89 81  9 76 21 34
 43 32  6 10 35 17 79 18 59 37 78 58 56 72 67 67 50 58 30 40 84 18 72 26  4 41 68 88 32 38
 93 95 74  4 98 33 22 68 90 60 81 65 73 34 12 82 27 22  5 87 63 49 33 82 11 82 83 59 66 27
 36 89 98 94 63 64 72 66 55 52 52 73 23 31 21 29 17 57 80 46 50 19 39 36 24  7 14 86 17 90
 53 62 56 15  5 45 58 62 39 89 18 12 97 17 96 34  8  1 58 92 10 39 80 63 77 89 42 24 11 32
 11 83 40  8 37 12 16 65 62 41  1 70 68 64 89 92 29 38 44 25  0 88  5 69 44 93 17 88 50 41
  0 53 25 13 22  3 94 54 33 42  8  2  1 61 37 76 60 29 13 32 80 64 47 91 13 43 18 80 79 92
 49 79 11 85 10 52 81 33 84 27 90 32 11 47 35 69 96 25 70  1 61 35 19 99 42 28 86 34 33 17
 31 55 15 37  6 67 75 33  8 43 74 63 85 30 52 35 47 55 90 98 83 80 76 59 15 34 38  0 72 58
 77 30 61 11 63 59 79 41 51 14 83 61  1 36 85 34 30 55 98 31 74 60 59 78 55 80 35 57 26 89
 19 27 31 38  1 17 82 65 24 17 31 54 62 35 45  0 85 42 38 21 26 97 73 21 23  7 82 35 95 43
  7 89  8 60 31 53 36 49 39 24  0 12 58 66 21 68 25 54 83 59 91 83 92 37 23  7  1 50 32 19
 27 22 20 36 49 79 40 88 96  2 35 12 63 10 41 64 48 13 69 43  6 89 94  9  0 58 63 82 51 92
 38 61 79 72 14 80 56 74  7 10 94 58 85 19 73 99 71 55 51 46 79 18 82 75 47 69 43 86 78 56
 27 26 91 12 15 30 76 47  3 74 43 84 31 87  6 79 50  2 69 39 18 27 28 47 39 31  1 25 87 31
 23 23 87 41 40 88 48 16  3 77 68 75 13  4 49 10 25 39 82 80 79 45 17 72 67 42 33 71 37  1
 54 94 94 83 17 68 88 65  4 37 63 52 57 13  9 92 78 67 43 87 25 66  0 32 69 13 86 24 56 16
 54 15 14 22 97 14 71 38 64 84 96 55 99  2 80 55 42 64 92 21 68 60 63 90 89 17 76  5 13 28
 65 86 81 81 17 25 42 42 99 86 55 76 49 16 96 99  8 10 85 62 53 54 15 37 49 56 61 82 19 21
 21 99 82 73 34 75 98 89 13  2 23 17 71  1 37 21 45 93 80 54 33 60  0 32  5 43 65  6 57  1
Soluzione
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define K 1000

int confrontoint(const void *arg1, const void *arg2) {
    int* a = (int*)arg1;
    int* b = arg2;
    return *a - *b;
}

int confrontorighe(const void *arg1, const void *arg2) {
    int* a = *(int**)arg1;
    int* b = *(int**)arg2;
    return a[0] - b[0];
}

int main() {
    FILE *fp;
    int i, j;
    // le maiuscole indicano la capacità della matrice, le minuscole  la
    // quantità di valori effettivamente contenuti
    int N, M, n, m;
    int **mat;
    char riga[K];
    char *token;

    fp = fopen("1-10-leggi-matrice-ordinamenti-input.txt", "r");
    if (fp == NULL) {
        printf("File non trovato\n");
        return 1;
    }

    N = 2;
    M = 2;
    // qui alloco un array dinamico di puntatori, ognuno a sua volta è un
    // array dinamico. Per ora ogni puntatore non punta a nulla.
    mat = malloc(N * sizeof(int*));
    n = 0;
    m = 0;
    for (i = 0; !feof(fp); i++) {
        if (i >= N) {
            N *= 2;
            // aggiungo puntatori cioè nuove righe
            mat = realloc(mat, N * sizeof(int *));
        }
        // è qui che alloco memoria per la riga i-esima (puntata dal puntatore
        // i-esimo)
        mat[i] = malloc(M * sizeof(int));
        fgets(riga, K, fp);
        token = strtok(riga, " ");
        for (j = 0; token != NULL; j++) {
            if (j >= M) {
                M *= 2;
                mat[i] = realloc(mat[i], M * sizeof(int));
                // qui va considerato che le righe devo essere tutte lunghe
                // uguali se no bisognerebbe fare una cosa più complicata.
                // Qui la realloc viene fatta solo riempiendo la prima riga.
            }
            sscanf(token, "%d", &mat[i][j]);
            token = strtok(NULL, " ");
        }
        
    }
    n = i;
    m = j;

    // stampa della matrice normale
    printf("Stampa della matrice letta:\n");
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            printf("%3d", mat[i][j]);
        }
        printf("\n");
    }


    printf("\n\nStampa della matrice ordinata riga per riga:\n");
    for (i = 0; i < n; i++) {
        qsort(mat[i], m, sizeof(int), confrontoint);
        for (j = 0; j < m; j++) {
            printf("%3d", mat[i][j]);
        }
        printf("\n");
    }


    printf("\n\nStampa della matrice ordinata anche per righe:\n");
    qsort(mat, n, sizeof(int*), confrontorighe);
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            printf("%3d", mat[i][j]);
        }
        printf("\n");
    }
}

Voti studenti

Scrivi un programma che legga i dati contenuti in un file di testo (testo riportato di seguito) e li inserisca in opportune strutture dati che rappresentino il registro dei voti per una materia. Il programma deve poi calcolare la media dei voti per ogni singolo studente e aggiungerla alla struttura dati (che quindi conterrà anche una variabile media). Il programma deve mostrare tutti i dati raccolti e calcolati sullo schermo e salvarli in un secondo file di testo. Nota che i cognomi possono essere formati da più parole e sono separati dai voti da un “:”, inoltre il numero di voti varia per ogni studente. L’array contenente i dati di ogni studente deve essere dinamico in modo che il programma funzioni per un qualsiasi numero di studenti.

File di input
Amici: 7.00 8.00 7.00
Biella: 8.00 9.50 7.00
Brescia: 5.00 7.50 9.00
Carolla: 7.00 8.50 8.50
Cunegatti: 7.00 7.00
De Bella: 4.00 4.00 4.50 5.00
De Vecchi: 8.00 10.00 6.00
Fumagalli: 8.50 6.00 4.50
Galimberti: 9.00 9.00 9.00
Germanò: 8.50 9.00 7.50
Gubellini: 8.00 10.00 7.00
Lepore: 5.50 4.00 3.00 5.00
Maconi: 7.50 5.00
Mariani: 8.00 8.00 7.00
Mattavelli: 9.00 9.50 8.50
Oggiano: 5.00 3.00 3.00 2.00
Passoni: 5.00 6.00 6.00 7.50
Pastori: 3.50 5.00 7.00 2.00
Pirovano: 6.50 7.50 7.50
Rudi: 9.50 10.00 10.00
Russell: 7.50 4.50
Sogos: 4.00 3.50 3.50 2.00
Tezza: 7.00 5.50 5.50
Varisco: 8.00 9.00 8.50
Output della soluzione
Amici: 7.00 8.00 7.00 - 7.33 
Biella: 8.00 9.50 7.00 - 8.17 
Brescia: 5.00 7.50 9.00 - 7.17 
Carolla: 7.00 8.50 8.50 - 8.00 
Cunegatti: 7.00 7.00 - 7.00 
De Bella: 4.00 4.00 4.50 5.00 - 4.38 
De Vecchi: 8.00 10.00 6.00 - 8.00 
Fumagalli: 8.50 6.00 4.50 - 6.33 
Galimberti: 9.00 9.00 9.00 - 9.00 
Germanò: 8.50 9.00 7.50 - 8.33 
Gubellini: 8.00 10.00 7.00 - 8.33 
Lepore: 5.50 4.00 3.00 5.00 - 4.38 
Maconi: 7.50 5.00 - 6.25 
Mariani: 8.00 8.00 7.00 - 7.67 
Mattavelli: 9.00 9.50 8.50 - 9.00 
Oggiano: 5.00 3.00 3.00 2.00 - 3.25 
Passoni: 5.00 6.00 6.00 7.50 - 6.13 
Pastori: 3.50 5.00 7.00 2.00 - 4.38 
Pirovano: 6.50 7.50 7.50 - 7.17 
Rudi: 9.50 10.00 10.00 - 9.83 
Russell: 7.50 4.50 - 6.00 
Sogos: 4.00 3.50 3.50 2.00 - 3.25 
Tezza: 7.00 5.50 5.50 - 6.00 
Varisco: 8.00 9.00 8.50 - 8.50 
Soluzione
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define M 20
#define K 200

typedef struct {
    char cognome[M];
    float voti[M];
    float media;
    int nvoti;
} Studente;

int main() {
    FILE *fp;
    Studente *elenco;
    char riga[K];
    int ntoken;
    int i, j, n, N = 4;

    fp = fopen("1-11-voti3.txt", "r");
    if (fp == NULL) {
        printf("errore nell'apertura del file.\n");
        return 1;
    }

    elenco = malloc(N * sizeof(Studente));
    if (elenco == NULL) {
        printf("Errore nell'allocazione della memoria.\n");
        return 1;
    }

    for (i = 0; !feof(fp); i++) {
        fgets(riga, K, fp);

        if (i >= N) {
            N *= 2;
            elenco = realloc(elenco, N * sizeof(Studente));
            if (elenco == NULL) {
                printf("Errore nell'allocazione della memoria.\n");
                return 1;
            }
        }
        ntoken = sscanf(riga, "%[^:]: %f %f %f %f", elenco[i].cognome,
                        &elenco[i].voti[0], &elenco[i].voti[1],
                        &elenco[i].voti[2], &elenco[i].voti[3]);
        elenco[i].nvoti = ntoken - 1;
    }
    n = i;
    fclose(fp);

    // calcolo della media
    for (i = 0; i < n; i++) {
        elenco[i].media = 0;
        for (j = 0; j < elenco[i].nvoti; j++) {
            elenco[i].media += elenco[i].voti[j];
        }
        elenco[i].media /= elenco[i].nvoti;
    }

    // stampo tutto con una funzione
    for (i = 0; i < n; i++) {
        printf("Studente: %12s - Media: %5.2f - Voti: ", elenco[i].cognome,
               elenco[i].media);
        for (j = 0; j < elenco[i].nvoti; j++) {
            printf("%3.1f ", elenco[i].voti[j]);
        }
        printf("\n");
    }

    // scrivo in un secondo file
    fp = fopen("1-11-voti3-out.txt", "w");
    if (fp == NULL) {
        printf("Apertura in scrittura del file fallita.\n");
        return 2;
    }
    for (i = 0; i < n; i++) {
        fprintf(fp, "%s: ", elenco[i].cognome);
        for (j = 0; j < elenco[i].nvoti; j++) {
            fprintf(fp, "%.2f ", elenco[i].voti[j]);
        }
        fprintf(fp, "- %.2f ", elenco[i].media);
        fprintf(fp, "\n");
    }
    fclose(fp);
}

Array e Matrici di Stringhe

La gestione delle stringhe in maniera del tutto dinamica è piuttosto complessa ed è utile solo in casi particolari. Per questo motivo almeno le stringhe continueremo a gestirle in maniera classica.

Lettura lista stringhe da file e ordinamento

Leggi l’elenco di nomi dal file di input e inseriscili in un array dinamico. Ordina poi l’elenco in ordine alfabetico.

Soluzione

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define M 20

int main() {
    FILE *fp;
    int i, j, N, n;
    char (*nomi)[M];

    fp = fopen("2-01-lista-nomi.txt", "r");
    if (fp == NULL) {
        printf("File non trovato\n");
        return 1;
    }

    N = 4;
    nomi = malloc(N * sizeof(char) * M);
    if (nomi == NULL) {
        printf("Non riesco ad allocare abbastanza memoria!");
        return 1;
    }

    for (i = 0; !feof(fp); i++) {
        if (i >= N) {
            nomi = realloc(nomi, N * sizeof(char) * M * 2);
            if (nomi == NULL) {
                printf("Non riesco ad allocare abbastanza memoria!");
                return 1;
            }
            N *= 2;
        }
        fscanf(fp, "%s", nomi[i]);
    }
    n = i;

    printf("Nomi non ordinati:\n");
    for (i = 0; i < n; i++) {
        printf("- %s\n", nomi[i]);
    }

    qsort(nomi, n, sizeof(char) * M, strcmp);
    // si lamenta un po' (warnings) perchè strcmp non ha esattamente il formato
    // che vorrebbe ma funziona

    printf("Nomi ordinati:\n");
    for (i = 0; i < n; i++) {
        printf("- %s\n", nomi[i]);
    }
}

Matrice di stringhe e ordinamenti

Leggi l’elenco di nomi dal file di input e inseriscili in un array dinamico. Inserisci poi i nomi in una lista di liste di nomi in cui in ogni riga ci sono nomi che iniziano con la stessa lettera. Ordina poi ogni riga in ordine alfabetico.

Soluzione
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define M 20

int main() {
    FILE *fp;
    int i, j, N, n, p, matcap, matsize;
    char (*nomi)[M];
    char (**mat)[M];
    int *sizes, *caps;

    fp = fopen("2-02-lista-nomi-to-matrice-ordinata.txt", "r");
    if (fp == NULL) {
        printf("File non trovato\n");
        return 1;
    }

    N = 4;
    nomi = malloc(N * sizeof(char) * M);

    for (i = 0; !feof(fp); i++) {
        if (i >= N) {
            nomi = realloc(nomi, N * sizeof(char) * M * 2);
            if (nomi == NULL) {
                printf("Non riesco ad allocare abbastanza memoria!");
                return 1;
            }
            N *= 2;
        }
        fscanf(fp, "%s", nomi[i]);
    }
    n = i;

    printf("Nomi letti:\n");
    for (i = 0; i < n; i++) {
        printf("- %s\n", nomi[i]);
    }

    // qsort(nomi, n, sizeof(char) * M, strcmp);
    // si lamenta un po (warnings) perchè strcmp non ha esattamente il formato
    // che vorrebbe ma funziona

    mat = malloc(1 * sizeof(char**));
    if (mat == NULL) {
        printf("Non riesco ad allocare abbastanza memoria!");
        return 1;
    }
    matcap = 1;
    matsize = 1;

    sizes = malloc(matcap * sizeof(int));
    caps = malloc(matcap * sizeof(int));
    for (i = 0; i < matcap; i++) {
        sizes[i] = 0;
        caps[i] = 0;
    }

    for (p = 0; p < n; p++) {
        i = 0;
        // printf("%d %s %s - ", sizes[i], nomi[p], mat[i][0]);
        while (sizes[i] != 0 && nomi[p][0] != mat[i][0][0]) {
            i++;
            if (i >= matcap) {
                mat = realloc(mat, matcap * 2 * sizeof(char**));
                if (mat == NULL) {
                    printf("Non riesco ad allocare abbastanza memoria!");
                    return 1;
                }
                matcap *= 2;
                sizes = realloc(sizes, matcap * sizeof(int));
                caps = realloc(caps, matcap * sizeof(int));
                for (j = matsize; j < matcap; j++) {
                    sizes[j] = 0;
                    caps[j] = 0;
                }
            }
            if (i >= matsize) {
                matsize++;
            }
        }
        // printf("matcap:%d matsize:%d - ", matcap, matsize);
        if (caps[i] == 0) {
            mat[i] = malloc(4 * sizeof(char) * M);
            if (mat[i] == NULL) {
                printf("Non riesco ad allocare abbastanza memoria!");
                return 1;
            }
            caps[i] = 4;
        }
        if (sizes[i] >= caps[i]) {
            mat[i] = realloc(mat[i], caps[i] * 2 * sizeof(char) * M);
            if (mat[i] == NULL) {
                printf("Non riesco ad allocare abbastanza memoria!");
                return 1;
            }
            caps[i] *= 2;
        }
        // printf("Scrivo %s in mat[%d][%d]\n", nomi[p], i, sizes[i]);
        strcpy(mat[i][sizes[i]], nomi[p]);
        sizes[i] += 1;
    }

    printf("\n\nStampa matrice:\n");
    for (i = 0; i < matsize; i++) {
        printf(" %c: ", mat[i][0][0]);
        for (j = 0; j < sizes[i]; j++) {
            printf("%s ", mat[i][j]);
        }
        printf("\n");
    }

    printf("\n\nRistampa matrice ordinata riga per riga:\n");
    for (i = 0; i < matsize; i++) {
        qsort(mat[i], sizes[i], sizeof(char)*M, strcmp);
        printf(" %c: ", mat[i][0][0]);
        for (j = 0; j < sizes[i]; j++) {
            printf("%s ", mat[i][j]);
        }
        printf("\n");
    }

    // per ordinare le righe fra loro il qsort non va bene perchè dovrei ordinare anche l'array sizes
    // per usarlo dovevo fare una struttura per ogni riga contenente sia l'array che la dimensione
}

Per curiosità riporto la soluzione di questo esercizio in Python, un linguaggio di alto livello che nasconde la gestione della memoria e delle strutture dati dinamiche. Come è evidente questo rende la scrittura e la comprensione del codice molto più semplice. Di contro si perde il controllo delle operazioni di basso livello e la possibiiltà di ottimizzare tali operazioni per compiti specifici.

Soluzione in Python
with open("2-02-lista-nomi-to-matrice-ordinata.txt", encoding='utf-8') as f:
    nomi = [riga.strip() for riga in f]

mat = {}
for nome in nomi:
    if nome[0] in mat:
        mat[nome[0]].append(nome)
    else:
        mat[nome[0]] = [nome]

mat = [val for key,val in mat.items()]
mat.sort()
for nomi in mat:
    print(nomi)

Dispensa di Informatica per il Liceo Scientifico delle Scienze Applicate - A cura di Francesco Tormene