[C++] Manipuler proprement un tableau... - Problème(s) pour manipuler un tableau

Bonjour tout le monde !

Je viens de commencer à programmer une petite application en C++, langage que je n’ai jamais vraiment appris (je connais Java et j’ai utilisé les ressources du Net pour me mettre à la prog en C/C++). J’ai un problème : je ne sais pas comment manipuler proprement un tableau.

En fait, mon programme gènere des grilles de Sudoku. J’utilise donc un tableau 9 * 9 pour stocker la grille, ce tableau étant crée dans ma fonction/fichier main. Mais comment modifier ce tableau via une classe GridGenerator qui est un objet comportant des fonctions pour génerer une grille valide de Sudoku ? Je connais l’existence des pointeurs, des références, du passage par valeur/variable/référence. Je pense globalement les comprendre. Cependant, en pratique je patauge un peu quant à la méthode la plus simple et “propre” à employer.

On ne peut pas faire un tableau de réference, ce qui aurait surement été le plus “esthetique”. Utiliser une déclaration du genre “extern int grid[9][9]” = je faisais ça quand j’ai fait une embauche de mon algo en C, mais c’est plutot contraire à l’esprit POO du C++ non ? Faut il obligatoirement utiliser des pointeurs, qui sont pas très “cool” à manipuler (toujours mettre *maVariable plutot que maVariable si c’était une référence) ?

Voilà, si quelqu’un a une idée d’une solution élégante à ce “problème”, je lui serais reconnaissant de l’indiquer :wink: :smiley:

Merci d’avance et bonne journée,
PoiZon

Je ne comprend pas trop ton problème mais perso, je créérais une class qui me génére une grille avec certaines variables propre au jeux et j’instancierais un vector de cette classe pour toutes les grilles.
'Fin, une idée comme ça, il y en a tellement.

Euh oui, j’ai peut être pas été tout à fait clair, c’est vrai… :ange: Desolé :ane:

En fait c’est assez simple, je bute certainement sur un truc très simple. Dans un fichier main.cpp je déclare 1 tableau de 9 lignes sur 9 colonnes appelé “grid” qui est… ma grille de Sudoku. Je l’a met dans “main” parce que cette variable est au coeur du programme, et beaucoup de classes et fonctions auront à la manipuler (pour ensuite créer une grille avec des chiffres cachés, pour afficher la dite grille…).
Maintenant, le truc c’est que je veux que cette grille “passe” dans une sorte d’“usine” (ma classe GridGenerator) qui ne fait que créer une grille remplie et valide. Seulement, je ne sais pas comment passer ma grille en argument à mon GridGenerator (la seule soluce que je vois c’est les pointeurs mais n’y a t-il pas un moyen plus élégant et simple ?).

Voilà j’espere m’être fait compris, si c’est tjs obscur, ask me :slight_smile: !

KarlKox : merci pour ta réponse. Je ne connais pas la notion de vector mais je vais regarder. Cependant, je pense qu’une solution plus simple doit exister. Ou bien j’ai pas compris la POO, mais je pensais que ma volonté de faire comme expliqué plus haut était en accord avec les notions de celle ci.

Bonne journée :oui: ,
PoiZon

Salut,

Un chti programme explicatif?

#define SIZE_TAB 9

#include<stdlib.h>
#include<time.h>

#include<stdio.h>


void MakeTab(unsigned short grid[SIZE_TAB][SIZE_TAB])
{
      //Initialisation du hasard
      srand( (unsigned int) time(NULL) )      

      for(int longu = 0; longu < SIZE_TAB; longu++)
            for(int large = 0; large < SIZE_TAB; large++)
                  grid[longu][large] = (rand() % 9) + 1;	//Force les nombres entre 0 et 10, c'est pas ça les sudoku? :P
}

void PrintTab(unsigned short grid[SIZE_TAB][SIZE_TAB])
{
      for(int longu = 0; longu < SIZE_TAB; longu++)
      {
            //Imprime les nombres de la ligne
            for(int large = 0; large < SIZE_TAB; large++)
                  printf( "%i, " ,grid[longu][large] );
            //Retourne à la fin des 9 nombre
            printf("\n");
      }
}

int main(int argc, char* argv[])
{
      //Mon chti tableau que je vais travailler (de 9 par 9)
      unsigned short grid[SIZE_TAB][SIZE_TAB];

      //Lancement de la procédure (envoie d'un tableau)
      MakeTab(grid);

      //Impression du tableau
      PrintTab(grid);

      getchar();

      return 0;
}


//PS: Les tableaux se passent TOUJOURS en pointeur c'est OBLIGE, du moins, c'est mon avi :P

Voilà, dans ce programme je fait un tableau qui est passé dans deux procédures (une pour créer le tableau et une autre pour l’afficher). Le passage de tableau se fait toujours par pointeur !

Mais je ne sais pas si qqun pourrait appuyer mes dires, ce serait plus sûr :paf:

Non. Il ne faut surtout pas préciser de dimensions, et passer par pointer (même chose).

void f(const int a[5][5]) {
  ...
}
void g(const int* const * a, int row, int col) {
  ...
}

La différence est dure à voir (j’ai mis des const, qui doivent bloquer l’écriture des valeurs de g) : dans le cas 1, le tableau est recopié case par case avant d’appeler la fonction (ou pendant), dans le cas 2 non.

La deuxième façon est à préférer.

Il ne faut pas se laisser berner par Java : les tableaux sont juste des objets comme des autres, avec une astuce de langage qui fait que l’opérateur [] permette d’accèder à un élément donné.

En C (ou C++, encore qu’on puisse faire pareil qu’en Java assez simplement ;)) les tableaux (ie: déclarés ainsi int x[]…[n]) sont des pointeurs sur des éléments contigües.

C’est pas vraiment la même chose :slight_smile: même si la puissance du C++ te permette de créer un template Array<T> disposant des mêmes opérations (et plus si affinitées)

Tu es sûr?

Je crois, et même je suis sûr que non. Il est clair que passer un tableau en paramètre n’est pas très “classe” mais c’est possible.

De toute façon si il y a un tableau de ce type

int tab[2];

"tab" est le pointeur du tableau, donc en envoyant "tab" dans la fonction on peut se dire que on envoie un pointeur (oui je sais mon raisonnement est exotique mais il est juste).


//Ce code marche
int* var = tab;
int* var2 = &tab[0];

PS: Je viens de tester, j’en suis sûr et certain. J’ai fais une classe avec constructeur/desctructeur et constructeur de copie.
Le constructeur de copie est appelée quand je passe une fois la classe dans une fonction mais AUCUN constructeur n’est appelé quand j’envoie un tableau de la classe dans une fonction.

j’ai bien dis ce que j’ai dis. En C :

f(int x[5][5]) = recopie
f(int x[][5]) = simple pointeur

Si tu passes un tableau de A (en faisant gaffe que ça va planter si héritage), c’est juste un pointeur sur des éléments de taille contigue.

(fin je sais pas quel code tu as compilé)

Ok,

Mais comment expliquer que une recopie se fasse alors que, quand je lance ce code :

class testeur
{
public:
     testeur(const testeur&)
     {
          printf("Constructeur de recopie\n");
     }
     
     ~testeur()
     {
          printf("Desctructeur de recopie\n");
     }

     testeur()
     {
          printf("Constructeur\n");
     }
};

void fonctest(testeur test[2][2])
{
     return;
}

int main(int argc, char* argv[])
{
     testeur test[2][2];
     fonctest(test);
}

Il n’y ait jamais la chaîne “Constructeur de recopie” qui apparaisse dans la console?
Mais seulement 4 fois “Constructeur” (2 * 2 cellules)

Et ceci quand la première dimension du tableau soit fixée ou non!

C’est ça qui me semble bizarre…

PS: Mais toi tu parles du C? ou du C++? Es-ce que ce serait différent? Mais ça me semblerait vraiment bizarre une telle différence.

En C, ça fonctionne comme ça :slight_smile: c’est tout. Pour le C++ je n’ai pas essayé, ni même essaierait plus.

Aussi, essaye quand même de foutre des champs dans ton objet… à priori, là, il ne recopie que la vtable (et encore) donc pas besoin d’appeler le constructeur de recopie (s’il est logique)

Ok maintenant je comprends mieux.

Finalement en y réfléchissant un peu la recopie entière en mémoire d’une classe C++ est un peu lourde. Et comme en C il n’y en a pas il est possible que les concepteurs de ces deux languages aient choisi des “chemins différents”.

Je me rappelais avoir lu que les tableaux étaient envoyés sous forme de pointeur, mais c’est bien dans un livre sur le C++ que j’ai lu ça. Je ne pensais pas que des différences pareilles pouvaient exister.

Non :slight_smile: c’est envoyé par pointeur tout le temps, sauf si tu fournis les dimensions à chaque fois :slight_smile: en gros toujours faire int** x au lieu de int x[2][3]. C’est tout.

En C, c’est pas objet, donc la copie c’est memcpy :slight_smile:

En C++, tu as la notion de constructeur par recopie et là sûrement que ça fait ça

Merci bien, en suivant vos idées et conseils j’ai réussi à faire ce que je voulais :super: !

En fait j’avais pas saisi toute la puissance et aussi complexité des pointeurs :wink: !

Pour info, voilà le code:

  • dans le fichier main.cpp :

int grid[9][9];                      // création de la grille
GridGenerator gen(grid);     // création du gridGenerator qui prend la grille (pointeur) en argument
gen.generateNewGrid();      // la grille est "transformée" en une grille valide de sudoku

  • dans GridGenerator.cpp/.h

int (*grid)[9];                // Un pointeur privé sur la grille est crée
GridGenerator (int (*_grid)[9])
{ grid = _grid; }