[C++] Linux, Stampa matrice
Ciao a tutti, sto scrivendo un esercizio x l'esame di informatica.
Devo stampare una matrice. Ho scritto questa funzione:
Se nel codice scrivo:
Va tutto bene, la matrice viene compilata con i numeri e visualizzata a schermo.
Pero' se scrivo
funzione select:
Quando provo a compilare con g++ ottengo:
Qualcuno puo' spiegarmi il problema?
Allego sotto il listato completo:
Grazie mille!!
Devo stampare una matrice. Ho scritto questa funzione:
//DIMC, DIMR sono costanti ed indicano il numero colonne e righe della matrice void print(int a[][DIMC]){ for(int i=0; i<DIMR; i++){ for(int j=0; j<DIMC; j++) cout << "\t"<<a[i][j]; cout << endl; } }
Se nel codice scrivo:
int m[DIMR][DIMC]; read(m); // è una funzione che riempie la matrice di interi a random print(m);
Va tutto bene, la matrice viene compilata con i numeri e visualizzata a schermo.
Pero' se scrivo
int** m2 = select(m, 2, 2); /* prende una sottomatrice della matrice m passata come parametro di dimensione 2x2, partendo dall'elemento in posizione 0,0 */ read(m2); print(m2);
funzione select:
int** select(int m[][DIMC], int nr, int nc){ //nr, nc sono numero righe e numero colonne della nuova matrice int** s = new int*[nr]; for(int i = 0; i<DIMR; i++) s[i]= new int[DIMC]; for(int r=0; r<nr; r++){ for(int c=0; c<nc; c++){ s[r][c] = m[r][c]; //cout << "\t" << m[r][c]; } cout << endl; } return s; }
Quando provo a compilare con g++ ottengo:
bog@bog-1215P:~$ g++ ese.cc ese.cc: In function ‘int main(int, char**)’: ese.cc:42:10: error: cannot convert ‘int**’ to ‘int (*)[5]’ for argument ‘1’ to ‘void print(int (*)[5])’
Qualcuno puo' spiegarmi il problema?
Allego sotto il listato completo:
#include <iostream> #include <stdlib.h> using namespace std; const int DIMR = 5; const int DIMC = 5; void read(int a[][DIMC]){ for (int i = 0; i<DIMR; i++){ for (int j=0; j<DIMC; j++){ //cout << "Elemento ["<<i<<"]["<<j<<"]: "; //cin >> a[i][j]; a[i][j] = rand() % 5; } } } void print(int a[][DIMC]){ for(int i=0; i<DIMR; i++){ for(int j=0; j<DIMC; j++) cout << "\t"<<a[i][j]; cout << endl; } } int** select(int m[][DIMC], int nr, int nc){ int** s = new int*[nr]; for(int i = 0; i<DIMR; i++) s[i]= new int[DIMC]; for(int r=0; r<nr; r++){ for(int c=0; c<nc; c++){ s[r][c] = m[r][c]; cout << "\t" << m[r][c]; } cout << endl; } return s; } int main (int argc, char *argv[]){ int m[DIMR][DIMC]; read(m); print(m); int** m2 = select(m, 2, 2); //read(m2); print(m2); }
Grazie mille!!
Risposte
Non è così che si rappresentano (normalmente) le sottomatrici. Si indicano di solito i seguenti valori:
1. puntatore al primo elemento della sottomatrice;
2. dimensioni della sottomatrice;
3. distanza in byte (o in elementi della matrice) tra righe successive della sottomatrice;
Questo è il metodo usato ad esempio in librerie come LAPACK. In un programma reale è il metodo che ti consiglio di adottare (anche solo perché ti permetterebbe di usare LAPACK ad un certo punto se scoprissi di averne bisogno).
Venendo invece al tuo problema. Immagino sia sufficiente osservare come la rappresentazione in memoria di un array di puntatori e di una matrice bidimensionale siano totalmente diversi e non è possibile passare da un tipo ad un altro in modo semplice e immediato. Non puoi insomma usare la tua funzione print per stampare la tua sottomatrice...
1. puntatore al primo elemento della sottomatrice;
2. dimensioni della sottomatrice;
3. distanza in byte (o in elementi della matrice) tra righe successive della sottomatrice;
Questo è il metodo usato ad esempio in librerie come LAPACK. In un programma reale è il metodo che ti consiglio di adottare (anche solo perché ti permetterebbe di usare LAPACK ad un certo punto se scoprissi di averne bisogno).
Venendo invece al tuo problema. Immagino sia sufficiente osservare come la rappresentazione in memoria di un array di puntatori e di una matrice bidimensionale siano totalmente diversi e non è possibile passare da un tipo ad un altro in modo semplice e immediato. Non puoi insomma usare la tua funzione print per stampare la tua sottomatrice...
ciao ... grazie di avermi risposto.
pero'... devo ammettere che non ho idea di cosa sia la libreria LAPACK. (cioè: so cos'è una libreria ma la LAPACK ... boh)
comunque non fa parte del corso, quindi dato che non la conosciamo non è possibile (per noi studenti) usarla.
Testo esercizio
dici che in quel stampamatrice.o il prof abbia gia' implementato il tutto con l'uso della libreria da te citata?
pero'... devo ammettere che non ho idea di cosa sia la libreria LAPACK. (cioè: so cos'è una libreria ma la LAPACK ... boh)
comunque non fa parte del corso, quindi dato che non la conosciamo non è possibile (per noi studenti) usarla.
Testo esercizio
2 Il file esercizio2.cc contiene un programma che manipola matrici di interi, statiche e di-
namiche (come matrici dinamiche si intendono array dinamici di array dinamici, come visto
a lezione).
Si scrivano le seguenti funzioni:
(a) la funzione alloca matrice che, presi come parametri il numero di righe e il nu-
mero di colonne della matrice, restituisca una matrice dinamica di interi allocando
dinamicamente la memoria necessaria;
(b) la procedura dealloca matrice che liberi correttamente tutta la memoria allocata dalla
matrice;
(c) la procedura seleziona che presi come parametri la matrice originale in forma statica,
le coordinate del primo elemento e le dimensioni di una sottomatrice (righe e colonne),
ritorni tale sottomatrice in forma dinamica.
e di-
La funzione stampa matrice si occupa di stampare a video gli elementi della matrice ed `
chiarata nel file stampamatrice.h, che viene fornito assieme al file oggetto stampamatrice.o.
Il programma esercizio2.cc dovr`
a essere quindi compilato utilizzando tale file.
Se ad esempio la matrice originale fosse costituita da 4 righe e 4 colonne
1 4 7 8
2 5 8 9
3 6 9 0
4 7 0 1
e i valori 2, 1, 2 e 3 come parametri di ingresso, il programma dovr`
a stampare a video:
8 9 0
9 0 1
e infine deallochera' la matrice allocata.
NOTE: Si supponga che sia responsabilit`
a dell’utente inserire valori tali che la sottomatrice
sia interamente contenuta nella matrice data.
dici che in quel stampamatrice.o il prof abbia gia' implementato il tutto con l'uso della libreria da te citata?
"BoG":
dici che in quel stampamatrice.o il prof abbia gia' implementato il tutto con l'uso della libreria da te citata?
LAPACK non si occupa della visualizzazione delle matrici, specialmente considerando che tu non usi matrici di LAPACK.
Semplicemente è una funzione che non c’era bisogno implementaste voi.
Ho guardato il testo dell'esercizio e non mi torna l'esempio.. La seconda matrice non è una sottomatrice della prima, piuttosto la sua trasposta lo è. Ma la trasposta non è la sottomatrice che è stata richiesta nell'esempio. Inoltre mi sembra che la funzione di stampa sia già stata correttamente implementata dal tuo professore.
ciao,
grazie per il tuo aiuto.
Ho appena notato di aver sbagliato a copiare la matrice di partenza giusta è:
1 2 3 4
4 5 6 7
7 8 9 0
8 9 0 1
Si, lo so, nel file "stampamatrice.o" c'è gia' implementata. Nella riga di commando del terminale infatti mi basta includerlo con un:
pero' avrei voluto realizzarla io una funzione di stampa. e' tutto qua!
grazie per il tuo aiuto.
Ho appena notato di aver sbagliato a copiare la matrice di partenza giusta è:
1 2 3 4
4 5 6 7
7 8 9 0
8 9 0 1
Si, lo so, nel file "stampamatrice.o" c'è gia' implementata. Nella riga di commando del terminale infatti mi basta includerlo con un:
g++ esercizio2.cc stampamatrice.o
pero' avrei voluto realizzarla io una funzione di stampa. e' tutto qua!
Ma nella funzione di stampa è principalmente sbagliato il tipo. Vuoi stampare una matrice rappresentata da un array di array dinamici, per cui il prototipo dovrebbe essere qualcosa del tipo:
in cui ho richiesto le dimensioni come parametro. Il codice interno è poi praticamente uguale..
void print(int **a, int r, int c);
in cui ho richiesto le dimensioni come parametro. Il codice interno è poi praticamente uguale..
pero' dovrei creare 2 funzioni di stampa!
una per
con firma
una per la sotto-matrice creata dinamicamente
con la firma
Bom, ora compila... devo sl trovare gli altri errori, mi da un
Grazie mille dell'aiuto.
una per
int m[RIG][COL];
con firma
void print(int m[][COL])
una per la sotto-matrice creata dinamicamente
int **m2 = split(m, 2,2,2,2);
con la firma
void print(int **m)
Bom, ora compila... devo sl trovare gli altri errori, mi da un
Segmentation fault
Grazie mille dell'aiuto.
Alcuni commenti:
Dato che usi rand() dovresti inizializzare il generatori di numeri casuali usando
Nel print trovo che dovresti mettere tra graffe e/o indentare il primo cout per facilitarne la comprensione. Nel senso per rendere esplicito il fatto che viene eseguito solo lui dal ciclo più interno.
---------------------------------------------------------
Ma select non deve richiedere 5 valori? Perché ne richiedi tre? Comunque non è necessario materialmente estrarre una matrice e infatti i tipi sottomatrice delle librerie professionali in genere non lo fanno.
Penso che possa essere arrivata l’ora di spiegarti come una matrice
Ciò che vede il C++ della matrice m è il seguente:
Nel caso di una matrice del tipo tridimensionale dividera i gruppi da due in raggruppamenti più grossi fino al numero più a sinistra.
Per mostrartelo prova a sostituire il tuo print con questo:
)
Ovviamente non funzione con un **a e una matrice creata come
perché in memoria è fatta in questo modo:
Questa è fondamentalmente la ragione per cui, nel campo professionale, una matrice è semplicemente un puntatore monodimensionale e si nasconde il tutto l’overload di operatori (che tu non hai visto). Ovviamente in C++, ma alla fine si fa così anche in c per questioni di performance
.
In ogni caso non è difficile da implementare un nuovo print del tipo
Dato che usi rand() dovresti inizializzare il generatori di numeri casuali usando
srand(time(NULL));prima del ciclo con dentro rand(). La funzione time richieda la libreria ctime (o se preferisci time.h).
Nel print trovo che dovresti mettere tra graffe e/o indentare il primo cout per facilitarne la comprensione. Nel senso per rendere esplicito il fatto che viene eseguito solo lui dal ciclo più interno.
---------------------------------------------------------
Ma select non deve richiedere 5 valori? Perché ne richiedi tre? Comunque non è necessario materialmente estrarre una matrice e infatti i tipi sottomatrice delle librerie professionali in genere non lo fanno.
Penso che possa essere arrivata l’ora di spiegarti come una matrice
int m[3][2] = { {1, 2}, {3, 4}, {5, 6} };è messa in memoria.
Ciò che vede il C++ della matrice m è il seguente:
1 2 3 4 5 6cioé vede una successione di numeri. A questo punto il numero più esterno la informa che deve dividere il codice in gruppi da due.
Nel caso di una matrice del tipo tridimensionale dividera i gruppi da due in raggruppamenti più grossi fino al numero più a sinistra.
Per mostrartelo prova a sostituire il tuo print con questo:
void print(int *a) { for(int i=0; i<DIMR; i++){ cout <<a[i*DIMC]; for(int j=1; j<DIMC; j++) { // ho aggiunto le parentesi per facilitare le lettura del codice cout << "\t"<<a[i*DIMC + j]; } cout << endl; } }chiamandolo però come
print(&m[0][0]);noterai che tutto funziona bene (anzi meglio dato che ho tolto la tabulazione iniziale

Ovviamente non funzione con un **a e una matrice creata come
a = new int*[n]; for(int i = 0; i != n; ++n) *(a+i) = new int[m];
perché in memoria è fatta in questo modo:
{&a[0][0]} ------ {&a[0][0], ... , &a[n-1][0]} ------ {a[0][0], ... , a[0][m-1]} ------ {a[n-1][0], ... , a[n-1][m-1]]non necessariamente ordinato in questo modo. Capisci che se scorri linearmente l’arrai partendo da a[0][0] esci dallo spazio allocato dopo n elementi.
Questa è fondamentalmente la ragione per cui, nel campo professionale, una matrice è semplicemente un puntatore monodimensionale e si nasconde il tutto l’overload di operatori (che tu non hai visto). Ovviamente in C++, ma alla fine si fa così anche in c per questioni di performance

In ogni caso non è difficile da implementare un nuovo print del tipo
void print(int **a, int r, int c)che stampi le cose nel modo giusto, d’altra parte puoi comunque accedere alla memoria come a[j]... è invece un po' più tedioso provare a farlo con l'aritmetica dei puntatori infatti dovresti scriverlo come *(*(a+i)+j).
hmm... per quello che riguarda la
rande la sua inizializzazione... l'ho fatto da qualche parte, ne sono sicuro... boh... comunque per la rappresentazione in memoria della matrice
a = new int*[n]; for(int i = 0; i != n; ++n) *(a+i) = new int[m];... molto interessante, grazie