PDA

Visualizza la versione completa : [C] problema con stampa_matrice allocata dinamicamente


mbistato
18-08-2014, 12:55
Ciao a tutti,

sto cercando di scrivere un programma in C che riesca a caricare una matrice da file e stamparla a video.

Il codice finora scritto è il seguente:


#include <stdio.h>#include <stdlib.h>
#define MAX_C 50
#define MAX_R 50


typedef char** matrix;
int R, C;
matrix matricevip;
void leggi_matrice(const char* nomefile, matrix m, int *r, int *c);
void stampa_matrice(matrix m, int r, int c);


int main(int argc, char *argv[])
{


char* nomefile = argv[1];


if(argc!=2)
{
printf("Numero di argomenti inseriti errato!\n");
exit(EXIT_FAILURE);
}
else
{
//metto la & prima delle variabili per indicare che sto effetuando un passaggio di parametri per riferimento (ovvero per indirizzo)
//e non per valore


leggi_matrice(nomefile, matricevip, &R, &C);


stampa_matrice(matricevip, R, C);


}


return 0;
}




void leggi_matrice(const char* nomefile, matrix m, int *r, int *c)
{
//**matricevip è un doppio puntatore(un puntatore per le righe e uno per le colonne)
char buffer[MAX_C], *res, temp;
int i = 0, j = 0;
FILE *ptrvip = fopen(nomefile, "r");
if(nomefile == NULL)
printf("Impossibile aprire il file %s\n", nomefile);
else
{
printf("File %s letto correttamente!\n\n", nomefile);
//Acquisizione numero di colonne
res = fgets(buffer, MAX_C, ptrvip);


while(res[i] != '\0')
{
*c = *c +1;
i++;
}
C = *c;


//Riposiziono il cursore all'inizio del file
fseek(ptrvip, 0, 0);




//Conto il numero della righe
while(1)
{
res = fgets(buffer, MAX_R, ptrvip);
if(res == NULL)
break;
*r = *r + 1;
}


R = *r;


//Allocazione dinamica della memoria
m = (char**) malloc (*c * sizeof(char*));//alloco lo spazio per le colonne
for(i = 0; i < *c; i++)
m[i] = (char*) malloc (*r * sizeof(char));//alloco lo spazio per le righe


//Riposiziono il cursore all'inizio del file
fseek(ptrvip, 0, 0);


//Caricamento della matrice da file


while(!feof(ptrvip))
{
for(i = 0; i < *r; i++)
for(j = 0; j < *c; j++)
{
fscanf(ptrvip, "%c", &temp);
if(temp != '\0')
m[i][j] = temp;


}


}


fclose(ptrvip);
}
}


void stampa_matrice(matrix m, int r, int c)
{
printf("\n");
int i,j;
for (i=0;i<r;++i)
{
for (j=0;j<c-1;++j)
printf("%c",m[i][j]);
printf("\n");
}
printf("\n");
}




La lettura del file e il caricamento della matrice va a buon fine, ma il programma smette di funzionare non appena richiamo la funzione "stampa_matrice".
Qualcuno è in grado di capire il perchè?

Grazie

torn24
18-08-2014, 13:48
int R, C;


Dichiari le variabili, ma non le inizializzi a 0, quindi le incrementi e poi utilizzi, sicuramente il loro valore non è quello che ti aspetti, probabile che nella funzione stampa superi le dimensioni della matrice.
fammi sapere se l'errore era questo.

mbistato
18-08-2014, 14:41
Ho inizializzato le variabili ma il problema persiste.

Il contenuto del mio file è il seguente:


JohnLennonXXXXX
PaulMcCartneyXX
GeorgeHarrisonX
RingoStarrXXXXX
StuartSutcliffe

Ho fatto una verifica facendomi stampare la matrice man mano che viene caricata modificando il seguente pezzo di codice:



while(!feof(ptrvip))
{
for(i = 0; i < R; i++)
for(j = 0; j < C; j++)
{
fscanf(ptrvip, "%c", &temp);
if(temp != '\0'){
m[i][j] = temp;
printf("%c", m[i][j]);
}
}
printf("\n");


}


Il risultato della stampa è:


JohnLennonXXXXX
PaulMcCartneyXX
GeorgeHarrisonX
RingoStarrXXXXX
StuartSutcliffee

In pratica mi stampa una "e" in più al fondo.

oregon
18-08-2014, 23:35
Nel codice esistono tanti problemi "minori" (ad esempio, che senso ha controllare con feof la fine del file se sai esattamente quanti caratteri leggere? Oppure controllare if(nomefile == NULL) invece di controllare l'handle restituito dalla fopen).

Ma la questione che genera l'errore è un'altra. Alla funzione leggi_matrice devi passare un puntatore a matrix (ovvero un puntatore triplo)

matrix *m

altrimenti non potrai mai modificarlo all'interno della funzione.

mbistato
19-08-2014, 08:21
Nel codice esistono tanti problemi "minori" (ad esempio, che senso ha controllare con feof la fine del file se sai esattamente quanti caratteri leggere? Oppure controllare if(nomefile == NULL) invece di controllare l'handle restituito dalla fopen).


Il testo del problema dice che non si conosce a priori la dimensione del file, ecco il motivo per cui uso feof.


Ma la questione che genera l'errore è un'altra. Alla funzione leggi_matrice devi passare un puntatore a matrix (ovvero un puntatore triplo)

matrix *m

altrimenti non potrai mai modificarlo all'interno della funzione.

Ho provato ma ottengo errori quando alloco lo spazio in memoria.



#include <stdio.h>
#include <stdlib.h>
#define MAX_C 50
#define MAX_R 50




typedef char** matrix;
int R, C;
matrix *matricevip;
void leggi_matrice(const char* nomefile, matrix *m, int *r, int *c);
void stampa_matrice(matrix *m, int r, int c);




int main(int argc, char *argv[])
{




char* nomefile = argv[1];




if(argc!=2)
{
printf("Numero di argomenti inseriti errato!\n");
exit(EXIT_FAILURE);
}
else
{
//metto la & prima delle variabili per indicare che sto effetuando un passaggio di parametri per riferimento (ovvero per indirizzo)
//e non per valore




leggi_matrice(nomefile, matricevip, &R, &C);




stampa_matrice(matricevip, R, C);




}




return 0;
}








void leggi_matrice(const char* nomefile, matrix *m, int *r, int *c)
{
//**matricevip è un doppio puntatore(un puntatore per le righe e uno per le colonne)
char buffer[MAX_C], *res, temp;
int i = 0, j = 0;
FILE *ptrvip;
if((ptrvip=fopen(nomefile, "r"))== NULL)
printf("Impossibile aprire il file %s\n", nomefile);
else
{
printf("File %s letto correttamente!\n\n", nomefile);
//Acquisizione numero di colonne
res = fgets(buffer, MAX_C, ptrvip);




while(res[i] != '\0')
{
*c = *c +1;
i++;
}
C = *c;




//Riposiziono il cursore all'inizio del file
fseek(ptrvip, 0, 0);








//Conto il numero della righe
while(1)
{
res = fgets(buffer, MAX_R, ptrvip);
if(res == NULL)
break;
*r = *r + 1;
}




R = *r;




//Allocazione dinamica della memoria
m = (char**) malloc (*c * sizeof(char*));//alloco lo spazio per le colonne
for(i = 0; i < *c; i++)
m[i] = (char*) malloc (*r * sizeof(char));//alloco lo spazio per le righe




//Riposiziono il cursore all'inizio del file
fseek(ptrvip, 0, 0);




//Caricamento della matrice da file




while(!feof(ptrvip))
{
for(i = 0; i < *r; i++)
for(j = 0; j < *c; j++)
{
fscanf(ptrvip, "%c", &temp);
if(temp != '\0')
m[i][j] = temp;




}




}




fclose(ptrvip);
}
}




void stampa_matrice(matrix *m, int r, int c)
{
printf("\n");
int i,j;
for (i=0;i<r;++i)
{
for (j=0;j<c-1;++j)
printf("%c",m[i][j]);
printf("\n");
}
printf("\n");
}



Domanda: come posso fare senza allocare dinamicamente la matrice in memoria?

Sto cercando la strada più semplice per farlo ma questi puntatori mi mettono il bastone tra le ruote :dhò:

Ho provato a fare quest'altra prova ma mi da errore quando richiamo le funzioni nel main in cui gli passo la matrice:



#include <stdio.h>
#include <stdlib.h>
#define MAX_C 50
#define MAX_R 50


int R, C;
void leggi_matrice(const char* nomefile, char mat[][MAX_C]);
void stampa_matrice(char mat [][MAX_C]);
void salva_file(const char* nomefile, char mat [][MAX_C]);
void delete_c(char mat [][MAX_C], int colonna);
void delete_r(char mat [][MAX_C], int riga);




int main(int argc, char *argv[])
{
char tipo;
char matricevip[MAX_R][MAX_C];
int numero;
char* nomefile = argv[1];


if(argc!=2)
{
printf("Numero di argomenti inseriti errato!\n");
exit(EXIT_FAILURE);
}
else
{
leggi_matrice(matricevip, nomefile);
stampa_matrice(matricevip);
}


printf("\n");
printf("Comando: ");
scanf("%c %d", &tipo, &numero);
//La riga che segue serve per togliere l'invio dal buffer


while(tipo != 'x'){
switch(tipo)
{
case 'c':


if(!numero){
printf("Errore: colonna non specificata!\n");
}
else if(numero < 0 || numero > C){
printf("Errore: il numero della colonna specificata eccede la dimenzione max del file!\n");
}
else
{
printf("test_1");
delete_c(matricevip, numero);
printf("Rimossa colonna %d", numero);
stampa_matrice(matricevip);


}


printf("Comando: ");
scanf("%c %d", tipo, &numero);
continue;


case 'r':
if(!numero){
printf("Errore: riga non specificata!\n");
}
else if(numero < 0 ||numero > R){
printf("Errore: il numero della riga specificata eccede la dimenzione max del file!\n");
}
else
{
delete_r(matricevip, numero);
printf("Rimossa riga %d", numero);
stampa_matrice(matricevip);


}


printf("Comando: ");
scanf("%c %d", tipo, &numero);
continue;


case 'q':
salva_file(nomefile, matricevip);
break;


default:
printf("Comando non valido");
exit(EXIT_FAILURE);
break;




}
}


return 0;
}




void leggi_matrice(const char* nomefile, char mat[MAX_R][MAX_C])
{
//**matricevip è un doppio puntatore(un puntatore per le righe e uno per le colonne)
char buffer[MAX_C], *res, temp;
int i = 0, j = 0, R = 0, C = 0;
FILE *ptrvip = fopen(nomefile, "r");
if(nomefile == NULL)
printf("Impossibile aprire il file %s\n", nomefile);
else
{
printf("File %s letto correttamente!\n\n", nomefile);
//Acquisizione numero di colonne
res = fgets(buffer, MAX_C, ptrvip);


while(res[i] != '\0')
{
C = C +1;
i++;
}


//Riposiziono il cursore all'inizio del file
fseek(ptrvip, 0, 0);




//Conto il numero della righe
while(1)
{
res = fgets(buffer, MAX_R, ptrvip);
if(res == NULL)
break;
R = R + 1;
}


//Riposiziono il cursore all'inizio del file
fseek(ptrvip, 0, 0);


//Caricamento della matrice da file


while(!feof(ptrvip))
{
for(i = 0; i < R; i++)
for(j = 0; j < C; j++)
{
fscanf(ptrvip, "%c", &temp);
if(temp != '\0')
mat[i][j] = temp;
}
printf("\n");


}


fclose(ptrvip);
}
}






void stampa_matrice(char mat[MAX_R][MAX_C])
{
printf("\n");
int i,j;
for (i=0;i<R;++i)
{
for (j=0;j<C;++j)
printf("%c", mat[i][j]);
}
printf("\n");
}




void salva_file(const char* nomefile, char mat[MAX_R][MAX_C]){
int i = 0, j = 0;
FILE *ptrvip = fopen(nomefile, "w");
if(nomefile == NULL)
printf("Impossibile aprire il file %s\n", nomefile);
else{
for(i=0; i<R; i++){
for(j=0; j<C; j++)
{
fprintf(ptrvip, "%c\n", mat[i][j]);
}
fprintf(ptrvip, "%c\n", '\n');
}
}


}


void delete_c(char mat[MAX_R][MAX_C], int colonna){


int i,j;
if(colonna == C-1)
C = C - 1;
else{
for(i=0; i<R; i++){
for(j=colonna; j<C; j++)
{
mat[i][j] = mat[i][j+1];
}
}
C = C - 1;
}
printf("La matrice è: \n");


stampa_matrice(mat);


}




void delete_r(char mat[MAX_R][MAX_C], int riga){


int i,j;
if(riga == R-1)
R = R - 1;
else{
for(i=riga; i<R-1; i++){
for(j=0; j<C; j++)
{
mat[i][j] = mat[i+1][j];
}
}
R = R - 1;
}
printf("La matrice è: \n");


stampa_matrice(mat);


}

oregon
19-08-2014, 14:41
Il testo del problema dice che non si conosce a priori la dimensione del file, ecco il motivo per cui uso feof.

Ma questo vale fino a quando non hai trovato R e C
Una volta trovate il numero di colonne e righe la feof non ti serve più



Domanda: come posso fare senza allocare dinamicamente la matrice in memoria?

Risposta: non puoi


Sto cercando la strada più semplice per farlo ma questi puntatori mi mettono il bastone tra le ruote

I puntatori sono il cuore di C. Se non li comprendi e non sai utilizzarli, praticamente non potrai utilizzare il C.

Ti ho detto di utilizzare un puntatore triplo ma non mi pare tu l'abbia fatto. Devi passare il puntatore a matricevip

leggi_matrice(&matricevip, nomefile);

modificando opportunamente la funzione leggi_matrice

mbistato
19-08-2014, 14:53
Si ok cmq ho risolto senza allocare la memoria dinamicamente :-D

oregon
19-08-2014, 15:08
Non puoi risolvere senza allocare la memoria se non sai quanto è grande il file ...

mbistato
19-08-2014, 15:39
Non puoi risolvere senza allocare la memoria se non sai quanto è grande il file ...

Dal testo del problema, so che il file non supera le dimensioni MAX_R x MAX_C

Ecco il codice funzionante:



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


#define MAX_R 50
#define MAX_C 50


int main(int narg, char *argv[])
{
char mat[MAX_R][MAX_C];
/*il vettore riga mi serve per andare a*/
char riga[MAX_R];
/*op sta per operazione e sarebbe quello che tu hai chiamato "tipo" nel tuo programma*/
char op;
/*posizione invece sarebbe il numero della riga o della colonna che hai scelto di cancellare*/
int pos;
/*eff_r ed eff_c sono rispettivamente il numero di righe e colonne della matrice di caratteri letta dal file*/
int eff_r, eff_c;


int i,j;
FILE *fp;
/*flag_ciclo è una variabile che useremo per ciclare l'esecuzione del programma finche non si verificano errori o finchè l'utente non esca
dal programma*/
int flag_ciclo;


if (narg!=2)
{
printf("Numero di parametri errato. \n");
exit (1);
}


fp = fopen(argv[1], "r");
if (fp == NULL)
{
printf("Errore nell'apertura del file %s \n", argv[1]);
exit (1);
}


i = 0;
/*leggo il file puntato da fp carattere per carattere e lo immagazzino in mat[i] (questo è quello che fa la funzione fgets).
Il while si conclude quando si arriva alla fine del file*/
while (fgets(mat[i],MAX_C,fp)!=NULL)
{
i++;
}
fclose(fp);


printf("File %s letto correttamente. \n", argv[1]);


/*memorizzo nella variabile effc la lunghezza di ogni riga (nota che sottraggo 1 perchè l'ultimo carattere presente nel vettore di stringhe
mat è il terminatore di stringa '\0' che ovviamete non devo contare). Dunque effc rappresenta il numero di colonne della matrice*/
eff_c = strlen(mat[0])-1;


/*analogamente eff_r sarà il numero di righe della matrice che era memorizzato nella variabile i incrementata
durante il while precedente*/
eff_r = i;


flag_ciclo = 0;
/*tale ciclo mi serve perchè ogni volta che do il comando da tastiera, a fine esecuzione, il programma deve permettermi di digitare
ulteriori comandi (in caso ti spiego meglio a voce)*/
while(!flag_ciclo)
{
printf("Comando: ");
/*La funzione gets brutalmente legge tutta la stringa corrispondente all’assegnazione e la funzione sscanf
la scompone nei due elementi nome e valore del nome. La funzione sscanf restituisce il numero di campi che sono stati letti, in
questo caso sarebbero 2: op e pos */
gets(riga);
j = sscanf(riga,"%c %d",&op,&pos);


/*Qui ci sono due controlli per verificare che il numero di riga o di colonna sia stato immesso sulla linea di comando*/
if ((op == 'r')&&(j == 1))
{
printf("Errore riga non specificata \n");
}
else if ((op == 'c')&&(j == 1))
{
printf("Errore colonna non specificata \n");
}
else
/*Se l'utente ha inserito il comando completo verifico in quale caso mi trovo:*/
switch(op)
{
case 'x':
printf("Programma terminato senza salvataggio. \n");
return 1;
break;
case 'r':
/*se la posizione inserita supera il massimo numero di righe della matrice e/o la posizione < 1, visualizzo l'errore*/
if ((pos > eff_r)||(pos < 1))
{
printf("Errore: riga non specificata correttamente \n");
break;
}
else
{
//Rimuovi riga: copio ciclicamente riga+1 in riga e tolgo una riga totale
printf("Rimossa riga %d. La matrice contiene:\n", pos);
for (pos = pos-1; pos < (eff_r-1); pos++)
{
/*la funzione strcpy copia il contenuto di mat[pos+1] in mat[pos]. In pratica per eliminare la riga, sovrascrivo
la riga+1 in riga */
strcpy(mat[pos],mat[pos+1]);
}
/*decremento, giustamente, il numero di righe della matrice*/
eff_r--;




//Stampo la matrice dopo l'operazione
for (i = 0; i<eff_r; i++)
{
for (j = 0; j< eff_c;j++)
{
printf("%c", mat[i][j]);
}
printf("\n");
}


}
break;
case 'c':
/*al solito controllo che la posizione della colonna scelta sia una posizione ammissibile, ovvero che non superi i
limiti inferiore e superiore*/
if ((pos > eff_c)||(pos < 1))
{
printf("Errore: colonna non specificata correttamente \n");
break;
}
else
{
//Rimuovi colonna: copio ciclicamente colonna+1 in colonna e tolgo una colonna totale
printf("Rimossa colonna %d. La matrice contiene:\n", pos);
for (i = 0; i < eff_r; i++)
for (j = pos - 1; j < (eff_c-1);j++)
{
/*qui avrei potuto utilizzare anche la funzione strcpy come fatto per le righe*/
mat[i][j] = mat[i][j+1];
}
eff_c--;


//Stampo la matrice dopo l'operazione
for (i = 0; i<eff_r; i++)
{
for (j = 0; j< eff_c;j++)
{
printf("%c", mat[i][j]);
}
printf("\n");
}
}
break;
case 'q':
//Salvo il file copiando il contenuto della matrice nel file.
fp = fopen (argv[1], "w");
if (fp == NULL)
{
printf("Errore nell'apertura del file %s in scrittura \n", argv[1]);
exit (1);
}
for (i = 0; i<eff_r; i++)
{
for (j = 0; j< eff_c;j++)
{
fprintf(fp,"%c", mat[i][j]);
}
fprintf(fp,"\n");
}
fclose(fp);
printf("Il file %s e' stato salvato correttamente. \n", argv[1]);
return 1;
break;
default:
printf("Errore: comando sconosciuto \n");
}
}








return 0;
}

oregon
19-08-2014, 17:01
Dal testo del problema, so che il file non supera le dimensioni MAX_R x MAX_C

Questo cambia le cose, così il problema è diverso. Avresti dovuto precisarlo prima ...

Loading