Problème pointeurs tableau multi c++!

Fermé
gudule - 20 août 2007 à 15:54
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 - 29 août 2007 à 18:33
Bonjour,
j'ai un petit souci avec les pointeurs que je pensais avoir compris. Voilà mon problème:
J'ai 2 codes qui initialisent les élément d'une matrice dynamiquement à l'aide d'un pointeur. Le premier fonctionne, c'est normal, mais pourquoi le second ne fonctionne pas?
Voici les codes:
#include <iostream>
using namespace std;


int main(int argc, char* argv[])
{ 
	int **matrice2d = new int*[5];
	int k = 0;
	for(int i=0;i<5;i++)
	{
		matrice2d[i]= new int[5];
		for(unsigned int j=0;j<5;j++)
		{
			matrice2d[i][j] = i;
			cout << matrice2d[i][j];
			cout << "  ";
		}
		cout << "\n";

	}
	return 0;
}

et voici le second qui ne marche pas:
#include <iostream>
using namespace std;


int main(int argc, char* argv[])
{ 
		int **matrice = new int*[5];
	int k=0;
	for(unsigned int i=0;i<5;i++)
	{
		*matrice = new int[5];
		for(unsigned int j=0;j<5;j++)
		{
			**matrice = k;
			cout << matrice[i][j];
			cout << "  ";
			*matrice++;
			k++;
		}
		matrice++;
		cout << "\n";

	}
}

Merci!

7 réponses

Excusez moi le 2ieme code n'est pas bon
voici le bon:
#include <iostream>
using namespace std;


int main(int argc, char* argv[])
{ 
		int **matrice = new int*[5];
	int k=0;
	for(unsigned int i=0;i<5;i++)
	{
		*matrice = new int[5];
		for(unsigned int j=0;j<5;j++)
		{
			**matrice = k;
			cout << **matrice;//voilà ce qui change!
			cout << "  ";
			*matrice++;//on fait pointer le pointeur sur l'entier suivant
			k++;
		}
		matrice++;//on fait pointer le pointeur sur le pointeur d'entier suivant 
		cout << "\n";

	}
}

mais ça ne marche toujours pas. Je comprends pas...
Merci de regarder ça!
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
21 août 2007 à 15:30
Je sais que ca ne répond pas vraiment à ta question mais la 1ère méthode me semble mieux que la première. En fait j'ai de sérieux doutes dans ta 2e méthode sur ce que fait l'incrémentation d'un pointeur. De toute façon l'utilisation des crochets est aussi efficace (complexité O(1)) qu'incrémenter un pointeur mais présente en plus l'avantage d'être lisible.

Voici le code que je te propose. Soit tu mets tout dans un même fichier (par exemple main.cpp), soit tu fais un fichier main.cpp et un fichier matrix_2d.hpp (cf commentaires) :
//---- matrix_2d.hpp-----
#include <cassert>
#include <iostream>

template <typename Tdata>
class matrix_2d{
    protected:
        unsigned nb_row;
        unsigned nb_column;
        Tdata **data;
    public:

        matrix_2d(unsigned nb_row0,unsigned nb_column0):
            nb_row(nb_row0),
            nb_column(nb_column0)
        {
            data = new Tdata*[nb_row];
            for(unsigned i=0;i<nb_row;++i) data[i] = new Tdata[nb_column];
        }

        inline unsigned get_nb_row() const{
            return nb_row;
        }

        inline unsigned get_nb_column() const{
            return nb_column;
        }

        inline const Tdata & get(unsigned row,unsigned col) const{
            assert(row < nb_row);
            assert(col < nb_column);
            return data[row][col];
        }

        inline void set(unsigned row,unsigned col,const Tdata & val){
            assert(row < nb_row);
            assert(col < nb_column);
             data[row][col] = val;
        }
};

template <typename Tdata>
std::ostream & operator << (std::ostream & out,const matrix_2d<Tdata> & m){
    unsigned nb_row = m.get_nb_row(),nb_col = m.get_nb_column();
    for(unsigned i=0;i<nb_row;++i){
        for(unsigned j=0;j<nb_col;++j){
            out << m.get(i,j) << '\t';
        }
        out << std::endl;
    }
    return out;
}

//---- matrix_2d.hpp-----

//---- main.cpp ---------
// #include "matrix_2d.hpp"
// #include <iostream>

int main(){
    std::cout << "Création de m:" << std::endl;
    matrix_2d<int> m(5,3);
    std::cout << m;
    std::cout << "Initialisation de m:" << std::endl;
    unsigned nb_row = m.get_nb_row(),nb_col = m.get_nb_column(),k=0;
    for(unsigned i=0;i<nb_row;++i){
        for(unsigned j=0;j<nb_col;++j){
            m.set(i,j,k++);
        }
    }
    std::cout << m;
    return 0;
}

A l'exécution ça donne :
Création de m:
0       0       0
0       0       0
0       0       0
0       0       0
0       0       0
Initialisation de m:
0       1       2
3       4       5
6       7       8
9       10      11
12      13      14

Petites recommandations :

1) Quand tu utilises des éléments de la STl (vector, cout, endl...) pense bien à préciser le "std::" pour que ça compile avec tous les compilateurs. Si tu trouves ça lourd, rajoute en début de fichier un
using namespace std;

Attention par contre à ne pas utiliser cette instruction dans un .hpp car sinon quiconque qui utilise ce fichier hpp en sera également victime. En fait le namespace std sert à étanchéifier les noms de classe de ton programme de ceux de la STL afin d'éviter les conflits. C'est pourquoi le using namespace std doit être utilisé avec des pincettes, et uniquement dans des fichiers cpp.

2) Pense à finir ton main par un "return 0", il est sensé retourné un int (le code d'éxecution). Inutile de passer à main un argc et un argv si tu ne les utilses pas.

Bonne chance
0
Bonjour,

J'ai bien compris ton premier code, mais pas du tout le second (du premier message).

Peux tu expliquer ce qu'est que tu souhaite faire avec le "**matrice = k;" STP ?

D'avance, merci
0
Bonjour,
Tout d'abord merci à mamiemando :)
Je n'ai en fait pas besoin d'une matrice, mais je m'intéressait à l'arithmétique des pointeurs... C'est vrai que même si elle fonctionnait, la 2eme méthode ne serait pas la plus facile à utiliser, mais je crois n'avoir pas compris encore pourquoi ça ne marche pas.

En réponse à Marc :
Le principe est que comme matrice correspond à l'adresse du 1er pointeur d'entier - (matrice+1) correspond à l'adresse du second, etc...- je pensais que je pouvais incrémenter le pointeur, afin qu'il pointe vers le pointeur d'entier suivant quand je passe à la ligne suivante.
De même incrémenter chaque pointeur d'entier pour le faire passer d'un entier à l'autre.
Quand on rentre dans la 2nde boucle, **matrice = k; assigne au premier élément du premier pointeur d'entier la valeur de k.
Si *matrice était correctement incrémenté, *matrice corresponderait à chaque itération de la 2nde boucle à l'adresse de l'entier suivant
et donc **matrice représenterait à chaque fois ce nouvel entier.
Si matrice était correctement incrémenté, matrice corresponderait à chaque itération de la 1ere boucle à l'adresse du pointeur d'entier suivant.
Je ne sais pas si je suis bien clair...
Quoi qu'il en soit ça ne marche pas, mais je trouvais l'idée intéressante de manipuler une foule de donnée à l'aide d'un seul pointeur **matrice.

Merci pour vos réponses :)

NB : Au fait à quoi correspondent les fichiers .hpp???
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
26 août 2007 à 23:43
Pour les pointeurs je t'avoue que sur le coup j'ai compris ce que tu voulais faire et je suis aussi surpris que toi que ça ne marche pas. Je pense que la syntaxe ne doit pas être tout à fait clean il faudrait voir ce que fait exactement l'opérateur ++.

Pour les fichiers hpp il s'agit simplement de fichier .h mais pour le C++, c'est à dire utilisant explicitement des headers C++ (ici cassert et iostream) et des notions spécifiques au C++ (ici le template). C'est une notation assez classique (par exemple utilisée dans la lib boost) mais pas forcément standard (par exemple QT nomme ses headers .h). Moi je trouve la notation hpp plus logique (après tout on parle bien de fichiers cpp) sachant qu'on parle parfois aussi de fichier .hxx (resp .cxx) ou .hh (resp .cc). Les éditeurs texte orientés développement C++ dignes de ce nom reconnaissent toutes les extensions pour la coloration syntaxique, donc tu prends celle qui te plaît le plus ;)

Peux-tu me dire si ton problème est résolu ou si tu as besoin de précisions (par exemple la méthode template si elle t'intéresse) ?

Bonne chance
0
Salut mamiemando,
Merci pour ta réponse. Comme tu as dit il faudrait voir ce que fait exactement ++ sur un pointeur. Je vais un peu regarder ça même si ça n'a de toute façon pas d'intéret pratique. Ta méthode avec les template est très bien, c'est d'ailleurs la méthode que j'utiliserais pour les matrices. Peut-être que j'utiliserais un tableau simple (ou vector) indicé en fonction de la ligne est de la colonne (vu dans une faq sur developper.com). Merci pour l'exemple avec les templates. N'étant encore que débutant en cpp, je ne sais pas encore bien exploiter la puissance de l'orientation objet et j'ai tendance à faire du C dans un document cpp. Si j'avais une question, ça serait sur la surcharge de l'opérateur <<
J'ai vu qu'il fallait s'arranger pour qu'il retourne cout afin de pouvoir enchaîner les appels. Mais comment ça s'exprimer synthaxiquement?
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
29 août 2007 à 18:33
Programmer en C++ comme en C ?

Concrètement rien ne t'empêche de programmer en C++ comme en C. Je veux dire il ne faut pas se forcer à faire des héritages si tu n'en as pas besoin. Pour moi les gros intérêts du C++ c'est les templates, la STL, la possiblité de pouvoir redéfinir des opérateurs, et les références. Du point de vue de la structure du programme, moi je fais juste des classes à la place des structures (comparé à du C) et le moins possible d'héritage. Donc au final la structure du programme ne change pas beaucoup, après chacun son style de programmation.

Bref tu peux garder ce style de programmation, ça ne pose aucun problème.

Implementer une matrice avec des std::vector ?

Pour ton implémentation de matrice, même si ça ne changera pas grand chose je t'incite à utiliser plutôt un Tdata ** qu'un std::vector<std::vector<Tdata> >, car un vector<T> n'est qu'une encapsulation d'un tableau classique du C de type T*, qui contrôle la taille du vecteur, l'espace alloué etc... Bref il rajoute un supplément d'information en mémoire dont tu n'as pas besoin dans ce cas précis. Ceci dit, d'un point de vue performance ça ne changera pas grand chose. Attention par contre à éviter les push_back si tu n'as pas fait de réserve pour les très gros vector (en particulier une très grosse matrice pour cette exemple) car sinon tes performances risquent de dégringoler à cause des réallocations induites par un push_back. Enfin là on parle de matrices vraiment très très grosses ;)

Définition de l'opérateur <<

Dans l'exemple que je t'ai donné je t'ai montré comment redéfinir l'opérateur <<. On ne peut pas vraiment parler de surcharge dans ce cas puisque l'opérateur << n'est pas défini à ce stade pour mon objet. De manière générale << ne retourne pas std::cout mais le std::ostream (flux ouvert en écriture) sur lequel il a écrit. Ca peut être std::cout, std::cerr, ou un std::ofstream. C'est important de retourner une référence sur ce std::ostream sinon effectivement tu ne peux pas enchaîner les << sur une même ligne. En effet quand tu écris ...
std::cout << matrice << ' ' << 6 << "plop" << std::endl;

... en pratique tout se passe comme si tu avais écris ...
(((((std::cout << matrice) << ' ') << 6) << "plop") << std::endl);

Tu l'auras compris, l'opérande à gauche du << doit retourner le flux modifié pour que ça ait une chance de marché. C'est pour celà qu'on retourne une référence sur ce flux (std::ostream &).

J'espère avoir éclairé ta lanterne, sinon n'hésite pas à repréciser tes questions

Bonne chance
0