Malloc un tableau sortingdimensionnel en C?

Je traduis du code MATLAB en C et le script que je convertis utilise beaucoup les tableaux 3D comportant 10 * 100 * 300 entrées complexes. La taille de la masortingce dépend également de l’entrée du capteur. Idéalement, la masortingce doit être allouée de manière dynamic. Jusqu’à présent, j’ai essayé deux approches, la première étant un tableau 1D plat le long de

value = array[x + (y*xSize) + (z*ySize*xSize)] 

Ce qui blesse mon cerveau à utiliser. J’ai aussi essayé un tableau d’un tableau de pointeurs

 int main () { int ***array = malloc(3*sizeof(int**)); int i, j; for (i = 0; i < 3; i++) { *array[i] = malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { array[i][j] = malloc(3*sizeof(int)); } } array[1][2][1] = 10; return 0; } 

Ce qui donne une erreur de segmentation lorsque j’essaie d’atsortingbuer des données.

Dans un monde parfait, j’aimerais utiliser la deuxième méthode avec la notation tableau pour une programmation plus propre et plus facile. Existe-t-il un meilleur moyen d’allouer de manière dynamic un tableau à trois dimensions en C?

J’opterais pour la première option (le tableau 1D unique) car cela vous donnerait un seul bloc de mémoire dans lequel jouer, plutôt que potentiellement des milliers de blocs de mémoire fragmentés

Si accéder à l’élément correct du tableau vous fait penser à cela, j’écrirais une méthode utilitaire pour convertir les emplacements x, y, z en un décalage dans le tableau 1D

 int offset(int x, int y, int z) { return (z * xSize * ySize) + (y * xSize) + x; } 

Comme d’autres l’ont déjà dit, il est probablement préférable d’allouer un bloc de mémoire contigu, puis de déterminer soi-même l’indexation. Vous pouvez écrire une fonction pour le faire si vous voulez. Mais comme vous semblez vouloir savoir comment traiter le cas de plusieurs malloc() , voici un exemple:

Premièrement, je définis une fonction free_data() , qui libère un int *** avec xlen et ylen comme les deux premières tailles. Nous n’avons pas besoin d’un paramètre zlen , tout comme free() ne prend pas la longueur du pointeur libéré.

 void free_data(int ***data, size_t xlen, size_t ylen) { size_t i, j; for (i=0; i < xlen; ++i) { if (data[i] != NULL) { for (j=0; j < ylen; ++j) free(data[i][j]); free(data[i]); } } free(data); } 

La fonction effectue une boucle sur les data du pointeur et découvre les i data[i] Ensuite, pour un pointeur int ** donné, il effectue une boucle sur celui-ci, recherchant le j th int * dans les data[i][j] , puis le libère. Il doit également libérer les data[i] une fois toutes les data[i][j] libérées, et enfin, il doit libérer les data lui-même.

Passons maintenant à la fonction d’allocation. La fonction est un peu compliquée par la vérification des erreurs. En particulier, dans la mesure où il y a 1 + xlen + xlen*ylen malloc appels, nous devons être en mesure de gérer une défaillance de l'un de ces appels et de libérer toute la mémoire allouée jusqu'à présent. Pour faciliter les choses, nous nous appuyons sur le fait que free(NULL) n’est pas opérationnel, nous définissons donc tous les pointeurs à un niveau donné égal à NULL avant de tenter de les allouer, de sorte que si une erreur se produit, nous pouvons libérer tous les pointeurs.

Autre que cela, la fonction est assez simple. Nous xlen abord un espace pour les valeurs xlen int ** , puis pour chacun de ces pointeurs xlen , nous ylen de l’espace pour les valeurs ylen int * , puis pour chacun de ces pointeurs xlen*ylen , nous zlen de l’espace pour les valeurs zlen int , ce qui nous donne une espace total pour les xlen*ylen*zlen int :

 int ***alloc_data(size_t xlen, size_t ylen, size_t zlen) { int ***p; size_t i, j; if ((p = malloc(xlen * sizeof *p)) == NULL) { perror("malloc 1"); return NULL; } for (i=0; i < xlen; ++i) p[i] = NULL; for (i=0; i < xlen; ++i) if ((p[i] = malloc(ylen * sizeof *p[i])) == NULL) { perror("malloc 2"); free_data(p, xlen, ylen); return NULL; } for (i=0; i < xlen; ++i) for (j=0; j < ylen; ++j) p[i][j] = NULL; for (i=0; i < xlen; ++i) for (j=0; j < ylen; ++j) if ((p[i][j] = malloc(zlen * sizeof *p[i][j])) == NULL) { perror("malloc 3"); free_data(p, xlen, ylen); return NULL; } return p; } 

Notez que j’ai un peu simplifié les appels à malloc : en général, vous ne devez pas transtyper la valeur de retour de malloc et spécifier l’object que vous affectez comme opérande à l’opérateur sizeof au lieu de son type. Cela rend les appels malloc plus simples à écrire et moins sujets aux erreurs. Vous devez inclure stdlib.h pour malloc .

Voici un programme de test utilisant les deux fonctions ci-dessus:

 #include  #include  #include  #include  int main(void) { int ***data; size_t xlen = 10; size_t ylen = 100; size_t zlen = 300; size_t i, j, k; srand((unsigned int)time(NULL)); if ((data = alloc_data(xlen, ylen, zlen)) == NULL) return EXIT_FAILURE; for (i=0; i < xlen; ++i) for (j=0; j < ylen; ++j) for (k=0; k < zlen; ++k) data[i][j][k] = rand(); printf("%d\n", data[1][2][1]); free_data(data, xlen, ylen); return EXIT_SUCCESS; } 

Utilisez cette approche si vous le trouvez plus facile à utiliser. En général, cela sera plus lent que d'utiliser un bloc de mémoire contigu, mais si vous trouvez que la vitesse est satisfaisante avec le schéma ci-dessus, et si cela vous simplifie la vie, vous pouvez continuer à l'utiliser. Même si vous ne l'utilisez pas, il est bon de savoir comment faire fonctionner un tel système.

Êtes-vous sûr de devoir utiliser malloc ? C permet de créer des tableaux multidimentionnels de manière native:

 int a2[57][13][7]; 

Ou vous pouvez utiliser malloc de la manière suivante:

 int (*a)[13][7]; // imitates 3d array with unset 3rd dimension // actually it is a pointer to 2d arrays a = malloc(57 * sizeof *a); // allocates 57 rows a[35][7][3] = 12; // accessing element is conventional free(a); // freeing memory 

C89 ne dispose d’aucun moyen de faire ce que vous désirez, car un type de tableau en C ne peut être spécifié qu’avec des valeurs connues au moment de la compilation. Donc, pour éviter l’allocation dynamic insensée, vous devrez vous en tenir à la méthode unidimensionnelle. Vous pouvez utiliser une fonction pour faciliter ce processus

 int index(int x, int y, int z) { return x + (y*xSize) + (z*ySize*xSize); } int value = array[index(a, b, c)]; 

En C99, vous pouvez utiliser une syntaxe de tableau ordinaire même si les dimensions sont des valeurs d’exécution:

 int (*array)[X][Y][Z] = (int(*)[X][Y][Z])malloc(sizeof *p); // fill... int value = (*array)[a][b][c]; 

Cependant, cela ne fonctionne qu’avec des tableaux locaux non statiques.

Oh, je déteste l’allocation de tableaux Malloc ^^

Voici une version correcte, en gros c’était juste une ligne incorrecte:

 int main () { int ***array = (int***)malloc(3*sizeof(int**)); int i, j; for (i = 0; i < 3; i++) { // Assign to array[i], not *array[i] (that would dereference an uninitialized pointer) array[i] = (int**)malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { array[i][j] = (int*)malloc(3*sizeof(int)); } } array[1][2][1] = 10; return 0; } 

De cette manière, vous ne pouvez allouer qu’un seul bloc de mémoire et le tableau dynamic se comporte comme un tableau statique (c.-à-d. Contiguïté de la même mémoire). Vous pouvez également libérer de la mémoire avec un seul disque libre (tableau), comme les tableaux 1D ordinaires.

 double*** arr3dAlloc(const int ind1, const int ind2, const int ind3) { int i; int j; double*** array = (double***) malloc( (ind1 * sizeof(double*)) + (ind1*ind2 * sizeof(double**)) + (ind1*ind2*ind3 * sizeof(double)) ); for(i = 0; i < ind1; ++i) { array[i] = (double**)(array + ind1) + i * ind2; for(j = 0; j < ind2; ++j) { array[i][j] = (double*)(array + ind1 + ind1*ind2) + i*ind2*ind3 + j*ind3; } } return array; } 

À propos du segfault, je suis presque sûr que quelqu’un d’autre l’a signalé, mais juste au cas où, il y aurait un ‘*’ supplémentaire dans la première ligne de la première boucle for

 for (i = 0; i < 3; i++) { *array[i] = malloc(3*sizeof(int*)); // ^ we dont want to deference array twice for (j = 0; j < 3; j++) { array[i][j] = malloc(3*sizeof(int)); } } 

essayez ce qui suit:

  for (i = 0; i < 3; i++) { array[i] = malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { array[i][j] = malloc(3*sizeof(int)); } } 

J’espère que ceci vous aidera!!!!

Lors de l’allocation de mémoire pour un tableau 2D à l’intérieur d’un tableau 3D, affectez la mémoire allouée au tableau [i] et non au * tableau [i]. Cela fonctionnera sans erreur de segmentation.

Voici votre programme

 int main () { int ***array = malloc(3*sizeof(int**)); int i, j; for (i = 0; i < 3; i++) { array[i] = malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { array[i][j] = malloc(3*sizeof(int)); } } array[1][2][1] = 10; return 0; 

}

Vous vous forcez à percevoir ceci comme deux manières fondamentalement différentes d’allouer un tableau 3D. Cette perception est renforcée par deux détails de différenciation définitifs: 1) la seconde méthode utilise plusieurs niveaux d’ indirection pour accéder aux éléments réels, 2) la seconde méthode alloue indépendamment les masortingces 1D de niveau inférieur.

Mais pourquoi insistez-vous pour allouer les baies 1D de niveau inférieur de manière indépendante ? Tu n’as pas à faire ça. Et une fois que vous en avez tenu compte, vous devez savoir qu’il existe une troisième méthode de construction de votre masortingce 3D.

 int ***array3d = malloc(3 * sizeof(int **)); int **array2d = malloc(3 * 3 * sizeof(int *)); int *array1d = malloc(3 * 3 * 3 * sizeof(int)); for (size_t i = 0; i < 3; i++) { array3d[i] = array2d + i * 3; for (size_t j = 0; j < 3; j++) array3d[i][j] = array1d + i * 3 * 3 + j * 3; } array[1][2][1] = 10; 

Si vous examinez de près cette méthode d’allocation, vous constaterez qu’en fin de compte, il s’agit à peu près de la même chose que votre deuxième méthode: elle construit une structure de tableau à trois niveaux en utilisant des pointeurs intermédiaires à chaque niveau d’indirection. La seule différence est qu’il pré-alloue au préalable la mémoire pour chaque niveau d’indirection indirectionnel, "en une fois", au lieu de faire plusieurs appels malloc répétitifs. Le cycle suivant répartit simplement cette mémoire préallouée entre les sous-tableaux (c’est-à-dire qu’il initialise simplement les pointeurs).

Cependant, si vous regardez encore plus près, vous remarquerez également que la mémoire réelle des éléments de tableau (les int qui stockent les valeurs réelles) est allouée de la même manière que dans votre première méthode: malloc(3 * 3 * 3 * sizeof(int)); - comme un tableau plat et contigu.

Maintenant, si vous y réfléchissez, vous devez comprendre que cette troisième méthode n’est pas très différente de la première. Ils utilisent tous deux un tableau plat de taille xSize * ySize * zSize pour stocker les données. La seule différence réelle ici est la méthode que nous utilisons pour calculer l’index d’access à ces données non hiérarchiques. Dans la première méthode, nous calculions l’indice à la volée comme

 array1d[z * ySize * xSize + y * xSize + x] 

dans la troisième méthode, nous pré-calculons à l'avance les pointeurs vers les éléments du tableau, en utilisant essentiellement la même formule, stockons les résultats précalculés dans des tableaux supplémentaires et les récupérons ultérieurement à l'aide de la syntaxe d'access "naturelle" au tableau

 array3d[x][y][x] 

La question ici est de savoir si ce calcul préalable vaut l’effort supplémentaire et la mémoire supplémentaire. La réponse est: généralement non, ce n'est pas. En dépensant cette mémoire supplémentaire, vous ne retirerez aucun avantage de performances appréciable (il est probable que cela ralentira votre code).

La seule situation dans laquelle votre deuxième méthode pourrait être utile est celle qui concerne un tableau véritablement déchiqueté / irrégulier : un tableau multidimensionnel fragmenté avec certaines parties de sous-tableaux manquantes / non utilisées ou de taille réduite. Par exemple, si certains sous-tableaux 1D ou 2D de votre tableau 3D sont connus pour ne contenir que des zéros, vous pouvez décider de ne pas les stocker du tout en mémoire et de définir les pointeurs correspondants sur NULL. Cela impliquerait l'utilisation de votre deuxième méthode, dans laquelle les sous-tableaux sont alloués (ou non alloués) indépendamment. Si les données sont volumineuses, les économies de mémoire obtenues pourraient en valoir la peine.

Notez également que s’il s’agit de tableaux de 3 dimensions ou plus, les méthodes de répartition première / deuxième / troisième peuvent être utilisées ensemble, simultanément pour différents niveaux d’indirection. Vous pouvez décider de mettre en œuvre des tableaux 2D à l'aide de la première méthode, puis de les combiner dans un tableau 3D à l'aide de la deuxième méthode.

Ci-dessous le code pour les allocations de mémoire 3D:

 int row3d = 4; int column3d = 4; int height3d =4; int val3d =10; int ***arr3d = (int***)malloc (row3d*sizeof(int**)); for (int i =0 ; i 

ajoutez #include “stdlib.h” et supprimez le * de * tableau [i] et il fonctionnera une fois compilé dans gcc 4.4.1 sur Ubuntu

aussi, si vous ajoutez des instructions d’impression, vous pourrez trouver vos bugs plus rapidement

 #include  #include  int main () { int ***array = malloc(3*sizeof(int**)); int i, j; printf("%s\n","OK"); for (i = 0; i < 3; i++) { printf("i = %i \n",i); array[i] = malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { printf("i,j = %i,%i \n",i,j); array[i][j] = malloc(3*sizeof(int)); } } array[1][2][1] = 10; return 0; } 
 #include #include #define MAXX 3 #define MAXY 4 #define MAXZ 5 main() { int ***p,i,j; p=(int ***) malloc(MAXX * sizeof(int **)); for(i=0;i < MAXX;i++) { p[i]=(int **)malloc(MAXY * sizeof(int *)); for(j=0;j < MAXY;j++) p[i][j]=(int *)malloc(MAXZ * sizeof(int)); } for(k=0;k < MAXZ;k++) for(i=0;i < MAXX;i++) for(j=0;j < MAXY;j++) p[i][j][k]= < something >; } 

Cela devrait fonctionner, vous ne dressez pas la valeur de retour de malloc

 #include  int main () { int ***array = (int ***) malloc(3*sizeof(int**)); int i, j; for (i = 0; i < 3; i++) { array[i] = (int **)malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { array[i][j] = (int *)malloc(3*sizeof(int)); } } array[1][2][1] = 10; printf("%d\n", array[1][2][1]); return 0; } 

Lien de travail: http://ideone.com/X2mcb8