j'insiste sur ce que rouIoude a dit + on alloue un tableau de pointeurs, d'où le sizeof(int *) avec le '*' + on alloue de l'espace pour des int, d'où le sizeof(int) sans le '*'
Le Tout est souvent plus grand que la somme de ses parties.
On l'a vu, la manière "simple" de créer un tableau à 2 dimensions, il utilise int**ptab qui pointe sur un tableau de pointeurs, chaque pointeur pointant sur un tableau d'int. Si la seconde dimension du tableau est une constante, on a plus simple en utilisant int (*ptab)[5] qui ne nécessite qu'un malloc( nb_lignes * sizeof(int[5]) ). Sinon on peut utiliser la linéarisation. On crée un tableau de nb_colonnes*nb_lignes entiers en utilisant int* ptab qui s'initialise par malloc( nb_lignes * nb_colonnes * sizeof(int) ). Malheureusement contrairement aux 2 précédents qui s'utilisent en faisant ptab[i][j], celui-ci doit s'utiliser en faisant ptab[j*nb_colonnes+i]. Ce tableau n'a qu'une dimension mais permet d'émuler un tableau à 2 dimensions
Pour comprendre ces 3 manières, il suffit de les dessiner.
@Dalfab a écrit: > Si la seconde dimension du tableau est une constante, on a plus simple en utilisant int (*ptab)[5] qui ne nécessite qu'un malloc( nb_lignes * sizeof(int[5]) OK je fais: int *tab = malloc(nbLignes * sizeof(int[5])); Je n'ai pas de problème avec ça, mais comment j'écris l'équivalent de tab[i][j] ?
Le Tout est souvent plus grand que la somme de ses parties.
Ca m'a l'air assez complexe mais j'ai compris le principe. Je vais essayer. Et du coup si on veut un tableau à trois dimensions il faut un tableau de pointeurs de pointeurs de pointeurs auxquels on affecte chacun un tableau de pointeurs de pointeurs auxquels on affecte chacun un tableau de pointeurs auxquels on affecte chacun une variable allouée dynamiquement?
Par contre j'ai essayé de décrire la taille du tableau par une constante préprocesseur et mon IDE m'a mis l'erreur "']' attendu" que je ne comprend pas puisque j'ai écrit mon instructions comme ça:
int* tableau[NB_COLONNES_TABLEAU_MAP];
- Edité par SniffierPond 10 janvier 2022 à 12:43:54
On peut voir la définition de la constante préprocesseur ?
Tu as eu plusieurs solutions, alors attention à ne pas mélanger les solutions. Je t'ai donné celle qu'on voit souvent en premier. (ton discours et ton code semble être deux solutions différentes).
Ton code correspond à la première solution de dalfab.
Ne fait qu'une seule chose à la fois.
Commence déjà avec le tableau à 2 dimensions, après on verra !
Il y a aussi ce sujet relativement récent dans lequel on a discuté de différentes méthodes permettant d'allouer dynamiquement des tableaux à plusieurs dimensions :
@rouIoude : Pas la peine t'énerver sur moi. Ce qui est simple pour toi ne l'est peut être pas pour d'autres. La méthode que tu indiques est une méthode classique et bien connue, et qui est souvent la première qui vient à l'esprit aux programmeurs C parce qu'on l'a vue tellement de fois dans les centaines de codes qui font traditionnellement comme cela depuis que le C existe.
Cependant, je ne la qualifierais pas de simple personnellement (c'est une opinion, on n'est pas obligés d'être d'accord).
En tout état de cause, le lien vers le fil précédent donne du code de programmes illustratifs en exemples pour ta méthode et d'autres, y compris celles rappelées par Dalfab ci-dessus, ce que personne n'a fait pour le moment sur ce fil.
Si je reprend la suggestion de Dalfab: - #include <stdio.h> #include <stdlib.h> int main(void) { int n=4; int *tab = malloc(n*sizeof(int[5])); tab[3][2] = 333; } - J'obtiens: ak.c: In function 'main': ak.c:6:11: error: subscripted value is neither array nor pointer nor vector 6 | tab[3][2] = 333; | ^
Le Tout est souvent plus grand que la somme de ses parties.
Cela peut se faire avec une variable avec la notation VLA et un compilateur C99 comme illustré par cet exemple :
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t colonnes = 5;
size_t lignes = 10;
int truc = 0;
int (*tableau2D_dyn)[colonnes] = malloc(lignes * sizeof(*tableau2D_dyn));
for (size_t i = 0; i < lignes; i++)
for (size_t j = 0; j < colonnes; j++)
tableau2D_dyn[i][j] = truc++;
/* faire quelque chose avec le tableau */
free(tableau2D_dyn);
return 0;
}
cela permet de passer ce tableau à une fonction void print_array(size_t lignes, size_t colonnes, int array[][colonnes]); comme illustré dans cet autre fil auquel je me référais, qui fonctionnera de la même manière en C99 que le tableau 2D soit alloué dynamiquement ou statiquement et quelle que soit la dimension du tableau car on alloue une mémoire contiguë.
Dire que cette méthode est moins "simple" que de faire 11 malloc et autant de free en obtenant un tableau dont le contenu est dispersé et non contigu en mémoire et qui nécessitera un prototype différent pour être traité avec une fonction par rapport à un tableau 2D en dur est débattable, alors qu'il existe des moyens plus modernes de faire autrement et en une seule allocation.
Enfin, encore une fois, c'est une opinion, et on n'est pas obligés d'être d'accord.
$ gcc -g -Wall -Wextra -o vla vla.c
$ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./vla
==117321== Memcheck, a memory error detector
==117321== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==117321== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==117321== Command: ./vla
==117321==
array : int[2][3]
0 1 2
1 2 3
==117321==
==117321== HEAP SUMMARY:
==117321== in use at exit: 0 bytes in 0 blocks
==117321== total heap usage: 2 allocs, 2 frees, 1,048 bytes allocated
==117321==
==117321== All heap blocks were freed -- no leaks are possible
==117321==
==117321== For lists of detected and suppressed errors, rerun with: -s
==117321== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Ce qui est dommage est que c'est largement inutilisable directement dans une struct par exemple.
Edit: Ce qui est important de remarquer ici est que l'on utilise la notation VLA mais aussi qu'on déclare et définit un vla sur le tas et non la pile … donc a priori moins de souci d'explosion de pile.
Cela se généralise facilement à plusieurs dimensions.
Utiliser cette méthode est un challenge si on veut encapsuler tout ça dans une struct. Il faudrait passer le type du pointeur en void et caster à tire-larigot.
Edit 2: après réflexion, on ne crée pas un VLA sur le tas … on ne fait qu'utiliser la notation VLA.
$ gcc -g -Wall -Wextra -o vla2 vla2.c
$ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./vla2
==118767== Memcheck, a memory error detector
==118767== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==118767== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==118767== Command: ./vla2
==118767==
array : int[3][2]
0 1
1 2
2 3
==118767==
==118767== HEAP SUMMARY:
==118767== in use at exit: 0 bytes in 0 blocks
==118767== total heap usage: 2 allocs, 2 frees, 1,048 bytes allocated
==118767==
==118767== All heap blocks were freed -- no leaks are possible
==118767==
==118767== For lists of detected and suppressed errors, rerun with: -s
==118767== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Cette dernière version pourrait même être étendue simplement dans une struct avec un membre flexible … ce serait à creuser.
> Effectivement le VLA est encore plus simple : (...) Mais, ce n'est peut-être pas ce que recherche le PO.
Le code que tu postes :
#include <stdio.h>
int main(void)
{
int x=4;
int y=5;
int tab[x][y];
return 0;
}
n'est pas équivalent. Ce code déclare un tableau dans la pile, avec les limitations que cela comporte (la taille de la pile est limitée). Ce programme n'utilise pas du tout le tas. Si tu lances Valgrind dessus, il te confirmera que "total heap usage: 0 allocs, 0 frees, 0 bytes allocated".
Le code que je propose utilise le tas :
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t colonnes = 5;
size_t lignes = 10;
int truc = 0;
int (*tableau2D_dyn)[colonnes] = malloc(lignes * sizeof(*tableau2D_dyn));
for (size_t i = 0; i < lignes; i++)
for (size_t j = 0; j < colonnes; j++)
tableau2D_dyn[i][j] = truc++;
/* faire quelque chose avec le tableau */
free(tableau2D_dyn);
return 0;
}
Sinon l'utilisation d'un membre flexible dans uns structure n'est pas possible avec ce type de tableau. On peut au mieux caster avant l'utilisation, mais cela revient à cacher le calcul d'indice (genre i*width+j) dans le cast et le déréférencement ; ce qui en soi est inutile.
Tu veux sûrement parler de l'écho que faisait ton post au mien qui le précédait de plusieurs heures... mais rassures toi, je ne me serais pas permis cette réflexion O:-)
L'utilisation d'un membre flexible est une piste intéressante pour utiliser ces mécanismes en relation avec une struct, où on ne peut pas définir des types VLA.
Pour le membre flexible de struct, j'ai commis ceci :
#include <stdio.h>
#include <stdlib.h>
struct dyn_thing {
size_t col;
size_t lig;
int t2D[];
};
int main(void)
{
size_t col = 5;
size_t lig = 10;
int truc = 0;
struct dyn_thing * dt = malloc(sizeof(*dt) + sizeof(int) * col * lig);
dt->col = col;
dt->lig = lig;
int (*t2D)[col] = (void *)dt->t2D;
for (size_t i = 0; i < lig; i++)
for (size_t j = 0; j < col; j++)
t2D[i][j] = truc++;
free(dt);
return 0;
}
La ligne 19 pourrait être remplacée par une macro appelée juste comme make2D(t2D, dt) qui permette d'utiliser t2D ensuite dans la fonction avec la notation [][].
Cela fonctionne en C99, qui a introduit le membre flexible de struct outre les VLA et la possibilité d'affecter des types pointeurs sur VLA qui sont modifiables à l'exécution.
Le membre flexible doit être la fin de la struct, ce qui signifie qu'il ne peut y en avoir qu'un.
Avec gcc Valgrind ne bronche pas sur ce code.
$ gcc -g -Wall -Werror temp.c
$ valgrind ./a.out
==12525== Memcheck, a memory error detector
==12525== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12525== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==12525== Command: ./a.out
==12525==
==12525==
==12525== HEAP SUMMARY:
==12525== in use at exit: 0 bytes in 0 blocks
==12525== total heap usage: 1 allocs, 1 frees, 216 bytes allocated
==12525==
==12525== All heap blocks were freed -- no leaks are possible
==12525==
==12525== For counts of detected and suppressed errors, rerun with: -v
==12525== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
sans passer par une variable sur le stack … mais du coup comme je le disais, les casts ne sont qu'un ersatz compliqué d'un calcul d'indice …
Edit: les editions étant ce qu'elles sont, tu pourras constater tout de même (rien qu'avec la réaction de Rouloude en fait) l'antériorité … bref l'important étant de montrer ce genre de manipulations … je suppose.
> sans passer par une variable sur le stack … mais du coup comme je le disais, les casts ne sont qu'un ersatz compliqué d'un calcul d'indice …
Oui, je vois ce que tu veux dire. Cependant, en passant par une variable pointeur VLA qui rétablit la nature souhaitée du type du membre flexible (FAM), on n'a plus qu'à l'utiliser comme un tableau à 2 dimensions et on n'a pas besoin de cast compliqués. C'est fait une fois pour la fonction qui utilise le FAM.
C'est une technique courante, pour accéder à des parties de struct qui autrement nécessiteraient une syntaxe à rallonge, que d'en simplifier l'accès avec une variable pointeur locale à la fonction.
Sur les questions d' "écho" et d' "antériorité" je n'en fais pas un fromage (c'est d'ailleurs toi qui les soulève), mais je t'ai fait un MP car je crois qu'il y a un malentendu.
× 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.
En recherche d'emploi.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.