- ligne 14 le type tab n'existe pas ! (probablement que tu voulais utiliser le type tabstr) ?
- ligne 10 tu retourne une case extérieur à ton tableau ! Probablement que tu voulais retourner le tableau, or en C, il n'est pas possible de retourner un tableau* seulement son adresse. Tout en sachant que retourner l'adresse d'un tableau local à la fonction est une erreur car le tableau n'existe plus hors de la fonction.
- Si tu souhaites créer ton tableau dans une fonction, il va falloir utiliser l'allocation dynamique avec malloc !
Ou alors déclarer un tableau de taille fixe égale à 16 (le maxi possible).
tabstr grille[16][16];
for (int i=0; i < x;i++){ /* etc. */}
return grille;
Il faudra juste faire attention à ne pas perdre en route la taille réellement utilisée (la mettre dans une variable, ou bien l'adjoindre au tableau dans une structure).
Bon, à mon avis le problème vient d'un manque de vocabulaire. Le verbe "créer" est utilisé en long en large et à travers, sans exprimer réellement ce qu'on veut faire : déclarer, définir, réserver, allouer, initialiser etc.
1. Quand je vois
int main(){
tab grille;
grille = crea_grille(9); // j'essaie donc de créer un tableau 9x9
je me dis que la variable "grille" a été déclarée, donc y a pas à la créer, mais à l'initialiser.
2. Si on on sait que ça représente un tableau dont la taille ne bougera pas ensuite, pourquoi ne pas la déclarer comme telle ?
struct element {
int data;
};
int main() {
struct element a2[2][2];
...
avec tout bêtement sa taille ?
3. Ensuite il reste à l'initialiser avec ... un appel à une fonction qui sert à initialiser ?
init_array(2, a2);
Un programme pour montrer tout ça :
#include <stdio.h>
struct element {
int data;
};
void init_array(int size, struct element array[size][size]) {
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
array[r][c].data = 10*(r+1) + c + 1;
}
}
}
void print_array(int size, struct element array[size][size]) {
printf("size %d x %d :\n", size, size);
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
printf("%3d", array[r][c].data);
}
printf("\n");
}
}
int main() {
struct element a2[2][2];
struct element a3[3][3];
init_array(2, a2);
init_array(3, a3);
print_array(2, a2);
print_array(3, a3);
}
Et si la taille n'est pas connue à la conpilation mais fournie par l'utilisateur à l'éxécution? Ça marche des VLA à deux dimensions? Sinon, il faut utiliser des malloc dans la fonction de "création et initialisation". Et les débutants ne savent pas comment faire. Un "bon" cours le montrerait. Pire encore, on peut ramener le tableau 2D à un tableau 1D, mais il faut vraiment savoir comment jouer avec les indices. Je demande donc à dyd de préciser ce qu'il veut faire.
Le Tout est souvent plus grand que la somme de ses parties.
J'ai écrit du code simplifié pour initiialiser un tableau 2D défini avec une VLa: - #include <stdio.h> /* typedef struct{ int etat; int bomb; char contenu; } tabstr; */ typedef int tabstr;
// La longueur doit être précisée avant le tableau. void initialiser(int size, tabstr tab[size][size]) { for(int i=0; i<size; i++) { for(int j=0; j<size; j++) { tab[i][j] =(i+1)*10+j+1; } } }
Sinon, si on part sur l'idée d'une structure qui contient la représentation d'un tableau de taille arbitraire, on peut se taper l'allocation et la linéarisation.
#include <stdio.h>
#include <stdlib.h>
struct element {
int data;
};
struct grid {
int size;
struct element *array;
};
void grid_set(struct grid *g, int r, int c, struct element e) {
g->array[r * g->size + c] = e;
}
struct element grid_get(struct grid *g, int r, int c) {
return g->array[r * g->size + c];
}
void init_grid(int size, struct grid *g) {
g->size = size;
g->array = malloc(size * size *sizeof(struct element));
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
grid_set(g, r, c, (struct element) {
.data = 10*(r+1) + c + 1}
);
}
}
}
void delete_grid(struct grid *g) {
free(g->array);
g->array = NULL;
g->size = 0;
}
void print_grid(struct grid * g)
{
printf("grid with size %d x %d :\n", g->size, g->size);
for (int r = 0; r < g->size; r++) {
for (int c = 0; c < g->size; c++) {
printf("%3d", grid_get(g, r, c).data);
}
printf("\n");
}
}
void test_grid(int size) {
struct grid grid;
init_grid(size, & grid);
print_grid(& grid);
delete_grid(& grid);
}
int main()
{
test_grid(3);
test_grid(4);
}
Execution garantie sans fuite
$ valgrind ./prog
==17737== Memcheck, a memory error detector
==17737== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==17737== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==17737== Command: ./prog
==17737==
grid with size 3 x 3 :
11 12 13
21 22 23
31 32 33
grid with size 4 x 4 :
11 12 13 14
21 22 23 24
31 32 33 34
41 42 43 44
==17737==
==17737== HEAP SUMMARY:
==17737== in use at exit: 0 bytes in 0 blocks
==17737== total heap usage: 3 allocs, 3 frees, 1,124 bytes allocated
==17737==
==17737== All heap blocks were freed -- no leaks are possible
==17737==
==17737== For lists of detected and suppressed errors, rerun with: -s
==17737== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
---
Remarques
1. Un truc amusant (?), c'est que dans quasiment tous les cours/tutoriels que j'ai vu sur ce sujet de l'allocation dynamique, le type se sent obligé de faire une fonction pour allouer la structure "principale" : celle qui s'appelle "grid" ici, ou la structure list pour les chainages.
Ca vient probablement d'une obstination à persister dans la confusion douteuse entre liste et pointeur d'élément. En réalité L'allocation est nécessaire pour les maillons de la liste, ça n'oblige en rien d'allouer dynamiquement la structure de départ...
2. Maintenant qu'on a des structures, on peut aussi les retourner et faire une initialisation par affectation
3. Comme Noel approche, on peut aussi revoir les accesseurs
struct element * grid_at(struct grid *g, int r, int c) {
return & (g->array[r * g->size + c])
}
void grid_set(struct grid *g, int r, int c, struct element e) {
*grid_at(g, r, c) = e;
}
struct element grid_get(struct grid *g, int r, int c) {
return *grid_at(g,r,c);
}
Sinon, si on part sur l'idée d'une structure qui contient la représentation d'un tableau de taille arbitraire, on peut se taper l'allocation et la linéarisation. [...]
Alors oui … je dirai presque «évidemment». Ça sent fortement le TP sur le démineur, et à partir de là si on a envie d'avoir une modélisation propre il faut avoir quelque chose qui représente le plateau de jeu.
dyd a écrit:
Bonjour,
J'aurai besoin de votre aide pour pouvoir coder ma fonction qui va créer un tableau de structures à deux dimensions.
Le tableau sera soit de 9x9 ou soit de 16x16, taille indiquée par l'utilisateur avant de créer le tableau.
[...]
Ici on clairement un besoin réduit. Et tant qu'à faire autant se simplifier la vie comme propose Robun :
robun a écrit:
Ou alors déclarer un tableau de taille fixe égale à 16 (le maxi possible).[...]
Ici j'ajoute 2 à chaque dimension dans le but d'avoir une couronne de cellule particulière hors-jeu pour s'affranchir de certains tests pour vérifier si l'on se trouve en bord de plateau.
Dans le cadre d'un démineur, une cellule pourra soit être un mur (=une cellule de la couronne), soit une cellule vide, soit une cellule piégée. On peut imaginer quelque chose comme :
Si on décide ensuite d'intégrer dans une seule structure non seulement le plateau mais également l'avancement du jeu (même si une structure réservée à l'affichage serait plus classique dans un modèle MVC par exemple) on peut y rajouter :
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.