PDA

Visualizza la versione completa : [ C++ ] Leggere e stampare una Matrice da filetext


Riccardo88
09-01-2010, 17:19
Ciao,da poco ho iniziato a studiare le operazioni sui file.
Ora devo leggere una matrice di interi da un file di testo e stamparla a video, quindi devo sommare i suoi valori e stampare a video anche questo risultato.

Con un array mi viene perfettamente.


#include "fileArray.h"

void leggiArrayFile( vett v, int &r )
{
int register i;

fstream file;
file.open( SORGENTE, ios::in );

if( !file )
{
cout<<"Il file non esiste!\n";
}

else{
r = 0;
while( !file.eof() )
{
file>> v[ r ];
r++;
}
}

for( i = 0; i < r; i++ )
{
cout<< v[ i ] << " ";
}

file.close();
}

void sommaArrayFile( vett v, int &r )
{
int register i;
int sArray = 0;

for( i = 0; i < r; i++ )
{
sArray += v[ i ];
}

cout<<"\nLa somma degli interi contenuto nel file e' di: " << sArray;

}

Nel caso della matrice invece,per far stampare i numeri devo utilizzare un metodo diverso e in ogni caso non me li stampa seguendo lo schema della matrice( righe e colonne ) ma uno sotto l'altro.



#include "FileMatrici.h"

void leggiMatriceFile( matrice m, int &r, int &c )
{
int register i, j;

fstream file;
file.open( SORGENTE, ios::in );

if( !file )
{
cout<<"Il file non esiste!\n";
}
else{
file>> r;
file>> c;
for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
file>> m[ i ][ j ];
}
cout<< "\n";
}
}

for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
cout<< m[ i ][ j ];
}
cout<<"\n";
}
file.close();

}

void sommaMatriceFile( matrice m, int &r, int &c )
{
int register i, j;
int sMatrice = 0;

for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
sMatrice += m[ i ][ j ];
}
}

cout<<"\nLa somma degli interi della matrice contenuti nel file e\' di: " << sMatrice << "\n";

}


In pratica in questo modo il primo numero scritto all'interno del file viene considerato riempimento.
Il file in questo caso deve essere scritto così:


16
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4

Dove 16 serve per far capire al ciclco che deve leggere 16 valori in totale.

Però io vorrei che il riempimento fosse calcolato,in base alla fine del file, così come viene fatto con l'array.
Cioè in questo modo:



r = 0;
c = 0;
while( !file.eof() )
{
file>> m[ r ][ c ];
r++;
c++;
}


In questo modo non bisogna aggiungere alcun numero alla matrice esistente nel file.
Come posso fare per integrare questo metodo senza che mi spari una serie di numeri enormi che non riguardano la matrice scritta nel file?
Grazie.

YuYevon
09-01-2010, 19:37
Qualcosa del genere?



#include <iostream>
#include <fstream>

#define r 3
#define c 4

using namespace std;

int main()
{
int x[r][c];
ifstream input_file;

input_file.open("nome_del_file");

for (unsigned int i = 0; i < r; i++) {
for (unsigned int j = 0; j < c; j++) {
if (! input_file.eof()) {
input_file >> x[i][j];
cout << x[i][j] << " ";
}
}
cout << endl;
}

input_file.close();

return 0;
}


In questo modo non c'è bisogno di indicare il numero degli elementi da leggere.

Riccardo88
09-01-2010, 19:51
Ciao,grazie della risposta,ma così r e c rimangono statici perchè definiti,quindi per eventuali cambi all'interno del file,dovrei modificare sempre il sorgente,invece vorrei che sia il programma stesso a calcolare di volta in volta la grandezza della matrice contenuta nel file e ad adattare il calcolo.

Ho provato a scrivere la stessa funzione che ho scritto per l'array,in "versione matrice"
così:



void leggiMatriceFile( matrice m, int &r, int &c )
{
int register i, j;

fstream file;
file.open( SORGENTE, ios::in );

if( !file )
{
cout<<"Il file non esiste!\n";
}
else{
r = 0;
c = 0;
while( file.eof() )
{
file>> m[ r ][ c ];
r++;
c++;
}
}

for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
cout<< m[ i ][ j ] << " ";
}
cout<<"\n";
}
file.close();

}


Ma così facendo non mi stampa niente e il risultato delle funzione somma è sempre = 0.
Potresti dirmi se si può adattare in qualche modo secondo quanto ho scritto qui,in modo che funzioni anche con la matrice oltre che con l'array?

YuYevon
09-01-2010, 19:58
Ma così facendo, cioè incrementando sia r che c ad ogni passo, ottieni l'effetto di leggere gli elementi solo nella diagonale principale (m[0][0], m[1][1], m[2][2] ecc...).

Io pensavo che conoscessi a priori le dimensioni della matrice, o al massimo runtime così avresti potuto ricorrere all'allocazione dinamica. Comunque a questo punto puoi fare una così: leggi il file riga per riga con il metodo getline() (http://www.cplusplus.com/reference/iostream/istream/getline/), estrai dalla stringa ottenuta i numeri con la funzione strtok() (http://www.cplusplus.com/reference/clibrary/cstring/strtok/) e li converti in interi con atoi() (http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/), assegnandoli poi alla matrice. Chiaramente, a seconda di quanti numeri ci sono nella stringa saprai quanti elementi ha una riga.

E' probabile che esista una soluzione più C++ like, ma al momento non mi viene in mente altro.

ignaziodeblasi
09-01-2010, 20:10
Oppure puoi considerare la matrice come un array normale con un solo indice disinteressandoti di r e c;
Altrimenti ancora puoi controllare se hai letto un newline e incrementare r(perchè come ti ha detto YuYevon incrementando sempre sia r che c inserisci solo gli elementi della diagonale principale )..
Forse è un pò troppo C like come soluzione :zizi:

Riccardo88
09-01-2010, 22:57
Caspita è vero! Non ci avevo pensato eheheh,svista :p
Comunque vorrei fare in modo che funzioni sempre,senza conoscere la dimensione della matrice contenuta nel file.
La soluzione che proponi è alquanto laboriosa,fino ad ora ho visto solo strtok();
Caspita pensavo fosse più semplice!
Ora mi cimento un altro pò,grazie ad entrambi. :)

Riccardo88
09-01-2010, 23:06
Mitico! Ho provato a scopiazzare quello che avevo scritto per l'array,e per non segnare solo la diagonale principale: ho integrato un for in un altro come solitamente si fa con le matrici,solo che gli ho dato come termine di ciclo !file.eof()
A questo punto ho incrementato gli indici fino alla fine del file e mi stampa tutto!
Senza dover mettere un valore iniziale per il riempimento che alterava la matrice nel file!



else{
for( r = 0; !file.eof(); r++ )
{
for( c = 0; !file.eof(); c++ )
{
file>> m[ r ][ c ];
}
}
}

Ora il problema è la stampa,in pratica non mi stampa la matrice per righe e colonne ma tutti i numeri in fila,come se non vedesse la struttura della matrice:



for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
cout<< m[ i ][ j ] << " ";
}
cout<<"\n";
}
file.close();

}


E' come se ignorasse il comando cout<<"\n";
alla fine di ogni riga,non capisco perchè non lo veda.

shodan
10-01-2010, 00:42
Originariamente inviato da Riccardo88


else{
for( r = 0; !file.eof(); r++ )
{
for( c = 0; !file.eof(); c++ )
{
file>> m[ r ][ c ];
}
}
}


L'idea è giusta, ma l'implementazione sbagliata. Dal ciclo interno esci solo quando il file è finito, non quando hai raggiunto il fine riga. In pratica hai trasformato la matrice in un array, col rischio di sforare l'indice massimo per le colonne.

Riccardo88
10-01-2010, 12:01
Ah vero,in effetti è come se leggesse un'unica riga.
Ma allora come scriveresti per fargli leggere le colonne correttamente?

EDIT:
Inserendo i riempimenti da main,e adattando il body.cpp così:


void leggiMatriceFile( matrice m, int &r, int &c )
{
int register i, j;

fstream file;
file.open( SORGENTE, ios::in );

if( !file )
{
cout<<"Il file non esiste!\n";
}
else{
for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
file>> m[ i ][ j ];
}
}
}

for( i = 0; i < r; i++ )
{
for( j = 0; j < c; j++ )
{
cout<< m[ i ][ j ] << " ";
}
cout<<"\n";
}
file.close();

}


Mi legge,stampa e calcola perfettamente la matrice,però bisogna appunto inserire i rimepimenti manualmente,però vorrei che il programma stesso da solo, capisse quanto è grande la matrice di volta in volta.

shodan
10-01-2010, 16:58
Premesso che non puoi scrivere oltre i limiti imposti alla matrice, devi adottare il metodo che ti ha indicato Yuvevon ( leggere con getline(), spezzare con strtok(), convertire con atoi() ).

Un modo più " C++ " per fare quanto indicato ( che adotterei io, ma che richiede che tra numero e numero ci siano solo spazi) può essere questo (richiede <string> e <sstream>):



else{
std::string line;
while( getline(file,line) ) {
c=0;
std::istringstream iss(line);
while ( iss >> m[r][c] ) c++;
r++;
}
}


Il procedimento di tokenizzazione e conversione è a carico dello istringstream.

Loading