[C] Stampare una matrice

floppyes
Ciao a tutti!
Ho creato questo semplice programma in C che acquisisce una serie di numeri e li stampa in matrice:
#include <stdio.h>
//Definisco dimensione matrice
#define DIM1 3
#define DIM2 3
int main () {
int matrice[DIM1][DIM2];
int i=0,j=0;
//Inserisco i numeri che compongono la matrice
printf("Inserisci i numeri della matrice:\n");
for(i=0; i<DIM1; i++) {
for(j=0; j<DIM2; j++) {
printf("==> ");
scanf("%d", &matrice[i][j]);
}
}
//Stampa matrice
for(i=0; i<DIM1; i++) {
for(j=0; j<DIM2; j++) {
printf("%d ",matrice[i][j]);
}
printf("\n");
}
return 0;
}

Le dimensioni della matrice sono definite attraverso la funzione
#define DIM

Fin qui tutto a posto, il programma funziona correttamente. Allora ho pensato di modificarlo facendo decidere all'utente di quante righe e quante colonne è formata la matrice. Con uno
scanf
l'utente decide il numero di righe e di colonne, inserisce poi tutti i numeri, ma a questo punto il programma al posto di stamparmi la matrice corretta, mi stampa solamente gli ultimi due valori che ho immesso.
#include <stdio.h>
int main () {
int righe=0, colonne=0;
int matrice[righe][colonne];
int i=0,j=0;
printf("Numero di righe: ");
scanf("%d", &righe);
printf("Numero di colonne: ");
scanf("%d", &colonne);
printf("Inserisci i numeri della matrice:\n");
for(i=0; i<righe; i++) {
for(j=0; j<colonne; j++) {
printf("==> ");
scanf("%d", &matrice[i][j]);
}
}
//Stampa matrice
for(i=0; i<righe; i++) {
for(j=0; j<colonne; j++) {
printf("%d",matrice[i][j]);
}
printf("\n");
}
return 0;
}

Non riesco a capire dove sbaglio, il codice "in teoria" dovrebbe essere identico, solo che ho aggiunto la possibilità di decidere le righe e le colonne!
Grazie
Ciaoo :)

Risposte
Bandit1
manco a farlo apposta abbiamo lo stesso problema

claudio862
int righe=0, colonne=0;
int matrice[righe][colonne];


"matrice" è un array 0x0. Qualunque valore assegni in seguito alle variabili "righe" e "colonne", ormai l'array è stato creato. Devi creare la matrice dinamicamente (con "malloc").

floppyes
Ciao!
Grazie mille ho risolto il problema, ecco il codice giusto:
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    // Funzione malloc per dichiarare la dimensione della matrice
    int *dim1;
    dim1 = (int*) malloc (sizeof(int) * 100);
    int *dim2;
    dim2 = (int*) malloc (sizeof(int) * 100);
    int i=0,j=0;
   
    // L'utente seleziona il numero di righe e di colonne
    printf("Numero di righe: ");
    scanf("%d", dim1);
    printf("Numero di colonne: ");
    scanf("%d", dim2);
       int matrice[*dim1][*dim2];
    
    // Qui l'utente inserisce tutti i numeri della matrice
    printf("Inserisci i numeri della matrice:\n");
    for(i=0; i<*dim1; i++) {
        for(j=0; j<*dim2; j++) {
            printf("==> ");
            scanf("%d", &matrice[i][j]);
            }
    }

    //Stampo la matrice completa
    for(i=0; i<*dim1; i++) {
        for(j=0; j<*dim2; j++) {
            printf("%d \t",matrice[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}


Grazie
Ciaoo :)

claudio862
Non era esattamente quello che avevo in mente quando ho suggerito di usare malloc. In senso stretto questo programma sembra corretto, ma è abbastanza assurdo.

Con malloc stai allocando una quantità di memoria esagerata. Allochi (sizeof(int) * 100) per ogni dimensione, ma una dimensione è un numero, quindi ti basterebbe (sizeof(int) * 1). O ancora meglio, usa un intero direttamente:

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

int main(void)
{
    int dim1, dim2;
    int i=0,j=0;

    // L'utente seleziona il numero di righe e di colonne
    printf("Numero di righe: ");
    scanf("%d", &dim1);
    printf("Numero di colonne: ");
    scanf("%d", &dim2);
       int matrice[dim1][dim2];

    // Qui l'utente inserisce tutti i numeri della matrice
    printf("Inserisci i numeri della matrice:\n");
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("==> ");
            scanf("%d", &matrice[i][j]);
            }
    }

    //Stampo la matrice completa
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("%d \t",matrice[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Questo programma è praticamente identico a quello del tuo primo post, semplicemente dichiaro la matrice dopo aver acquisito dim1 e dim2.


Il problema è che sto usando un array a lunghezza variabile (l'array "matrice"). Un array "canonico" è qualcosa del genere:

int arr[DIM];

dove DIM è una costante nota durante la compilazione (praticamente un numero, oppure un'espressione di soli numeri, senza alcuna variabile). In questo caso non è così, perché dim1 e dim2 vengono inserite dall'utente, e sono note solo a runtime. Quindi "matrice" è un array a lunghezza variabile.

Le ultime versioni del linguaggio C (C99 e C11, rispettivamente del 1999 e 2011) supportano questo tipo di array, quindi questo programma è corretto. La versione "originale" del C (ANSI o C89) invece non li supporta. Nemmeno in C++ sono supportati, e mai lo saranno.

Inoltre gli array a lunghezza variabile hanno diversi problemi: vengono allocati sullo stack, quindi se la lunghezza è troppo grande in genere la memoria viene corrotta. Inoltre non è possibile sapere se l'allocazione è andata a buon fine o meno.


Quello che intendevo con allocare dinamicamente la matrice era questo:

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

int main(void)
{
    int dim1, dim2;
    int i=0,j=0;

    // L'utente seleziona il numero di righe e di colonne
    printf("Numero di righe: ");
    scanf("%d", &dim1);
    printf("Numero di colonne: ");
    scanf("%d", &dim2);


    // Alloco dinamicamente la matrice.
    int **matrice = malloc(dim1 * sizeof(int*));
    for (i = 0; i < dim1; i++) {
        matrice[i] = malloc(dim2 * sizeof(int));
    }


    // Qui l'utente inserisce tutti i numeri della matrice
    printf("Inserisci i numeri della matrice:\n");
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("==> ");
            scanf("%d", &matrice[i][j]);
            }
    }

    //Stampo la matrice completa
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("%d \t",matrice[i][j]);
        }
        printf("\n");
    }


    // Libero la memoria allocata.
    for (i = 0; i < dim1; i++) {
        free(matrice[i]);
    }
    free(matrice);



    return 0;
}



Un'alternativa è usare un array monodimensionale per simulare una matrice. Per accedere all'elemento (i, j) devi accedere all'elemento (i + dim1 * j):

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

int main(void)
{
    int dim1, dim2;
    int i=0,j=0;

    // L'utente seleziona il numero di righe e di colonne
    printf("Numero di righe: ");
    scanf("%d", &dim1);
    printf("Numero di colonne: ");
    scanf("%d", &dim2);


    // Alloco dinamicamente la matrice.
    int *matrice = malloc(dim1 * dim2 * sizeof(int*));


    // Qui l'utente inserisce tutti i numeri della matrice
    printf("Inserisci i numeri della matrice:\n");
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("==> ");
            scanf("%d", &matrice[i + dim1 * j]);
            }
    }

    //Stampo la matrice completa
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("%d \t",matrice[i + dim1 * j]);
        }
        printf("\n");
    }


    // Libero la memoria allocata.
    free(matrice);



    return 0;
}



Infine, l'ultima alternativa è creare una matrice di dimensione prefissata, come hai fatto nel primo programma, ma usarne solo una parte:

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

#define DIM 100

int main(void)
{
    int dim1, dim2;
    int i=0,j=0;
    int matrice[DIM][DIM];

    // L'utente seleziona il numero di righe e di colonne
    printf("Numero di righe (max %d): ", DIM);
    scanf("%d", &dim1);
    printf("Numero di colonne (max %d): ", DIM);
    scanf("%d", &dim2);

    if (dim1 > DIM || dim2 > DIM) {
        printf("Scegli una matrice più piccola.\n");
        exit(EXIT_FAILURE);
    }

    // Qui l'utente inserisce tutti i numeri della matrice
    printf("Inserisci i numeri della matrice:\n");
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("==> ");
            scanf("%d", &matrice[i][j]);
            }
    }

    //Stampo la matrice completa
    for(i=0; i<dim1; i++) {
        for(j=0; j<dim2; j++) {
            printf("%d \t",matrice[i][j]);
        }
        printf("\n");
    }

    return 0;
}

floppyes
Ciao!

Grazie mille per tutta la spiegazione, adesso è tutto più chiaro. In effetti il modo più veloce è quello di dichiarare la matrice dopo aver determinato il numero di righe e colonne, però quello con la malloc è il più corretto allora mi segno quel metodo.

Una sola domanda:
// Libero la memoria allocata.
    free(matrice);


Con questa istruzione vado a liberare la memoria occupata dai miei dati? Elimino tutti i dati salvati e quindi posso immetterne di nuovi?

Grazie ancora :)
CiaoO!

claudio862
"floppyes":
// Libero la memoria allocata.
free(matrice);

Con questa istruzione vado a liberare la memoria occupata dai miei dati? Elimino tutti i dati salvati e quindi posso immetterne di nuovi?


No. Con malloc() ottieni un blocco di memoria utilizzabile. Con free() segnali che quel blocco non ti serve più *. Però mi sembra strano che tu conosca la prima funzione ma non la seconda. Stai seguendo un libro?

* Il compilatore ti prende in parola. Se tenterai di usare in seguito quella memoria, il comportamento del programma sarà indefinito. Nota anche che "indefinito" potrebbe sembrare corretto, ma non lo è.

floppyes
Ciao!

Si sto seguendo il deitel&deitel ed anche il K&R, però non avevo ancora ben capito come utilizzare la malloc all'interno del codice!

Grazie mille per la spiegazione :)

Howard_Wolowitz
Nel caso un'ulteriore riferimento sull'allocazione dinamica di un array multidimensionale lo puoi trovare qui:http://c-faq.com/aryptr/dynmuldimary.html.

vict85
La scelta del metodo dovrebbe riflettere le reali necessità del codice. Risulta in questo senso importante capire i vantaggi e gli svantaggi dei vari metodi.

floppyes
Ciao!

Ok grazie mille, devo provare a fare un pò di esercizi su questo argomento per vedere se torna tutto :D

Grazie ancora
Ciaoo!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.