Newsgroup: it.comp.lang.c++
Titolo: uso matrici

Ciao a tutti, ho un problema (da nuovo del C) sull'uso delle matrici:
definisco
int **MyMat;
poi chiamo una funzione di inizializzazione (con l'istruz (iniMat(MyMat)):
void iniMat(int  **MMat)
{
   MMat= new int *[4];
  for (char i=0;i<4;i++)
     MMat[i]=new int [4];
}
quindi tento di riempirla con fillMat(myMat) dove la fill è definita
void fillMat(int **MMat){
 for..
  for..
    MMat[i][j]=1;   // QUI MI Dà ERRORE
}
So che devo usare il passaggio per rifermineto ma se lo faccio il
compilatore mi dice che non può convertire un tipo  int*** in  int**.
Grazie mille a tutti.
Giuseppe

 poi chiamo una funzione di inizializzazione (con l'istruz (iniMat(MyMat)):
NOOOOOOOOOOOOOOOOOOOOOOOOOOO
classi e costruttori!!!
magari template :-D
nel c++ evita quanto piu' possibile costruzioni a basso livello ... tipo 
per esempio vettori di puntatori per le matrici se no scrivi codice C 
che solo per sfizio lo compili con un compilatore c++
template <class T>
class Matrix
{
T* data_;
size_t dim1_,dim2_;
Matrix(size_t a,size_t b){//inizializza matrice}
T& operator()(const size_t i,const size_t j) {return data_[i*dim2+j];}
//eccetera eccetera
};
-- 
Hai recensioni nel cassetto di musica, cinema, letteratura,fumetti??
Ascolta e pentiti e se hai tempo vergognati
http://tonysuper.altervista.org

 ha scritto nel messaggio
news:2np0pkF...@uni-berlin.de...


 Giuseppe
Ciao Giuseppe,
questi passaggi di puntatori T*** (con tre asterischi) erano quelli che con
il C++ volevamo dimenticare!
Una matrice d'interi è un int**, ma per passare una variabile per
riferimento, in C, si usa il puntatore e si ottiene l'improponibile (a mio
avviso) int***.
In C++ invece ci sono i reference, ma non è tanto questo il problema, quanto
invece il fatto, che, come ti hanno già suggerito, devi concepire in modo
nuovo i tuoi programmi.
Il problema non sta nemmeno nel fatto di utilizzare vector od altri
container STL, anche perché, a mio avviso, nel caso di semplici matrici di
cui sono note le dimensioni e queste rimangono costanti, sicuramente l'uso
dei vector è macchinoso almeno quanto la gestione con i puntatori.
Guarda il semplice esempio che ho fatto, a parte il fatto che esistono
sicuramente altri modi (anche migliori) per definire una matrice, attraverso
la definizione delle classi in C++ è possibile istruire il compilatore a
svolgere compiti "nuovi" (non che prima non si potessero utilizzare le
matrici, anche in C), ma dopo la definizione della classe e la sua
implementazione (che sarebbe meglio separarla dalla definzione, ma io mi
trovo bene così per piccoli esempietti veloci), la nostra applicazione può
creare tutte le matrici che vogliamo e consentirci di lavorarci su e di non
pensare più ai puntatori.
Mentre invece con la tua soluzione per ogni matrice che ti andavi a creare
di dovevi sempre portarti dietri i ** o i *** !
E' vero che ti crei funzioni che poi ti aiutano, ma se cambi ad esempio tipo
(da int a float ad esempio, perchè ti serve una matrice di float), ecco che
devi riscrivere il codice!
In questo caso, la classe m2d (il nome che ho utilizzato) diventa
utilizzabile proprio come se il tuo linguaggio di programmazione avesse
questo tipo nativo.
L'esempio l'ho fatto di fretta e sicuramente ci sono strade migliori, ma
questo per ora non m'interessa, l'importante è che tu capisca il salto che
devi fare per semplificarti la vita più avanti (se vuoi continuare a
programmare applicazioni sempre più complesse, bisogna semplificare e creare
astrazione, per questo il C è stato pressoché abbandonato).
Se il listato che vedi sotto ti dovesse risultare incomprensibile, ti devi
preoccupare il giusto, non troppo, e pensare invece che ti si presenta ora
la possibilità di apprendere il C++.
Esistono ottimi libri, anche scaricabili gratuitamente da internet, dove ci
sono ottime spiegazioni ed esempi (molto migliori dei miei), uno di questi è
Thinking C++ volume 1, di Bruce Eckel, cercalo sul motore di ricerca, se
t'interessa.
Di seguito un esempio di una possibile classe di base per semplici matrici
2d.
Ciao e auguroni.
#include <iostream>
#include <iomanip>
// dichiara una classe template che definisce una
// matrice bidimensionale di dimensioni note e costanti
template<typename T>
class m2d
{
        protected:
        T** m_matrix; // la via ai nostri dati nella matrice
        unsigned int row; // il numero di righe
        unsigned int col; // il numero di colonne
        public:
        // il costruttore
        m2d(unsigned int Row,unsigned int Col) : row(Row) , col(Col)
        {
                // alloca una matrice
                const T ZERO = static_cast<T>(0);
                m_matrix = new T*[row];
                for(unsigned int j=0;j<row;++j)
                {
                        // ottiene il puntatore alla j-esima riga
                        T* d = m_matrix[j] = new T[col];
                        // inizializza tutte le righe
                        for(unsigned int i=0;i<col;++i) *d++ = ZERO;
                }
        }
        // il costruttore di copia
        m2d(const m2d& M) : row(M.row) , col(M.col)
        {
                // alloca una matrice
                m_matrix = new T*[row];
                for(unsigned int j=0;j<row;++j)
                {
                        T* d = m_matrix[j] = new T[col];
                        T* s = M.m_matrix[j];
                        // copia le righe dalla matrice sorgente
                        for(unsigned int i=0;i<col;++i) *d++ = *s++;
                }
        }
        // il distruttore
        ~m2d()
        {
                // rimuove la matrice dalla memoria
                for(unsigned int j=0;j<row;++j)
                {
                        delete [] m_matrix[j];
                }
                delete [] m_matrix;
        }
        // la funzione membro fill riempie la matrice con un valore
        void fill(const T& val)
        {
                for (unsigned int j=0;j<row;++j)
                {
                        T* d = m_matrix[j];
                        for(unsigned int i=0;i<col;++i) *d++ = val;
                }
        }
        // la funzione membro at restituisce una reference all'elemento
        // di una matrice
        inline T& at(unsigned int Row,unsigned int Col) const
        {
                return m_matrix[Row][Col];
        }
        // overload dell'operatore << per la classe ostream
        // consente ad esempio di fare cout << matrice;
        friend std::ostream& operator<<(std::ostream& out, const m2d<T>& M)
        {
                 out.setf(std::ios::right);
                 for (unsigned int j=0;j<M.row;++j)
                 {
                        for(unsigned int i=0;i<M.col;++i)
                                out << std::setw(5) << M.at(j,i);
                        out << std::endl;
                 }
                 return out;
        }
};
int main()
{
        const unsigned int ROW=3;
        const unsigned int COL=12;
        m2d<int> M(ROW,COL);
        std::cout << "Matrice vuota:\n" << M << std::endl;
        M.fill(-1);
        for(unsigned int i=0;i<COL;++i) M.at(0,i)=static_cast<int>(i);
        M.at(ROW-1,COL-1)=99;
        m2d<int> M2(M);
        std::cout << "Matrice inizializzata:\n"
                << M << "\n" << "copia di matrice\n" << M2 << std::endl;
        m2d<float> M3(ROW,COL);
        M3.fill(1.5);
        std::cout << "Lo stesso codice sorgente crea ora una matrice di
numeri reali!\n";
        std::cout << M3 << "\nPremi INVIO per terminare...";
        std::cin.get();
        return 0;
}

 avviso) int***.
Tutto quanto stato detto è validissimo. C'è da aggiungere che vedere una 
matrice come array di puntatori (e quindi infine come puntatore di 
puntatori) era quasi obbligatorio in C, non necessario in C++.
Allocare una matrice come array di puntatori ai fini della prestazione è 
  dannoso, sia per le maggior numero di operazioni da fare quando si 
crea e quando si distrugge, sia perchè inevitabilmente rischi di 
frammentare la matrice in quanto il programma puo' allocare ogni riga (o 
colonna? mi confondo sempre) dove gli pare.
La soluzione piu' efficiente è quella di allocare un solo array di 
dimensioni N*M al quale accedere tramite un'opportuna interfaccia che 
simula una struttura bidimensionale (in gergo slicing).
Se ti interessa la compatibilita' di interfaccia con il C (e quindi 
vedere la matrice come array di puntatori alla quale accedere tramite 
[][]) ti consiglio di scaricare la ottima libreria TNT di Roland Pozo 
che ti evita di scriverti il codice a manina e soprattutto è frutto di 
studi attenti e quindi è sicuramente molto piu' ben scritta e raffinata 
di quello che un programmatore novizio puo' creare.
Se vuoi crearti le tue classi fatte secondo i tuoi gusti come esercizio 
per risparmiare fatica puoi usare <valarray> e <vector>.
Negli ultimi mesi ho scritto diversi post sulle classi di matrici ... 
cercali con google. Se ti interessa sappi che ho praticamente 
abbandonato il Fortran 90/95/2003 per il calcolo numerico, una volta 
realizzato che con buone classi il c++ è performante uguale (anzi, data 
la disponibilità attuale di ottimi compilatori c++  gratuiti - GNU, 
Intel, Microsoft, Borland rischia di essere addirittura piu' conveniente).


 per risparmiare fatica puoi usare <valarray> e <vector>.
sui vector non sono molto favorevole, parlando di matrici di dimensioni
costanti (ma sono gusti personali).
Personalmente quando conosco prima le dimensioni e queste sono costanti, mi
creo un array, anche se in generale sono un fedele osservante STL-ista.
ciao.