Comment pointer sur un espace 2D / 3D sur une mémoire préallouée

J’ai optimisé en mémoire un code que j’ai pour une utilisation intégrée. Cela fonctionne bien mais le résultat est que j’ai beaucoup de mallocs 1D, 2D et 3D et que je me libère au milieu de fonctions qui ralentissent le temps d’exécution.

Pour plusieurs raisons, j’ai décidé de modifier ma façon de procéder. Je veux allouer toute la mémoire que je peux avec un seul malloc au début de mon exécution et il suffit de pointer le bon espace mémoire où chaque masortingce doit être.

Pour info, j’exécute ceci sur x86 pour le moment donc je n’ai aucun problème d’espace mémoire. Je déclare mes tableaux de cette façon:

unsigned char *memory; memory = (unsigned char *)malloc(MYSIZE*sizeof(unsigned char)); type* p1; p1 = (type *)((int)memory + p1_offset); type** p2; p2 = (type **)((int)memory + p2_offset); for (int i=0 ; i<p2_height ; i++) { p2[i] = (type *)((int)p2 + p2_width*sizeof(type)); } 

Bien que cela fonctionne bien pour mon pointeur 1D, il me renvoie un segfault pour ma déclaration de pointeur 2D. J’ai vérifié mes décalages et ils sont bons comparés au pointeur de mémoire. Comme je ne suis pas habitué à cette façon de déclarer mes pointeurs, je ne comprends peut-être pas quelque chose ici, alors je serais heureux si quelqu’un pouvait m’expliquer davantage à propos de cette technique!

Vous déclarez p2 en tant que pointeur sur un tableau de pointeurs, et non sur un tableau à deux dimensions plat. Vous êtes également (édité pour plus de clarté): initialiser p2 avec un entier de déchets, puis le replacer en un pointeur et le déréférencer.

Édité pour append un exemple de code:

 #include  #include  #include  #include  /* Boilerplate to turn this into a MWE: */ #define MYSIZE 1024U typedef double elem_t; static const size_t p1_offset = 0, p2_offset = 512; /* Our buffer will hold W 1d elements and X*Y 2d elements. */ #define W 64U #define X 32U #define Y 2U typedef struct { elem_t array1[W]; elem_t array2[X][Y]; } spaces_t; /* Test driver: */ int main(void) { /* sizeof(unsigned char) is defined as 1. Do you mean to allocate an * array of MYSIZE bytes or MYSIZE elements of type? */ spaces_t * const memory = malloc(sizeof(spaces_t)); if (!memory) { perror("malloc"); exit(EXIT_FAILURE); } elem_t* p1 = memory->array1; elem_t* p2 = (elem_t*)(memory->array2); /* Never cast a pointer to int. It's not even legal. * Why does this assertion succeed? Why are memory and bad_idea * equal, but memory+1 and bad_idea+1 different by the size of both * of our arrays combined, minus one byte? */ const uintptr_t bad_idea = (uintptr_t)memory; assert( (uintptr_t)(memory+1) - (bad_idea+1) == sizeof(spaces_t) - 1 ); /* Let's initialize all the arrays. No segfaults? */ size_t i,j; for (i = 0; i < W; ++i) { *p1 = (elem_t)i; assert( memory->array1[i] == *p1 ); ++p1; } /* This is a lot faster when X is a power of 2: */ for (i = 0; i < X; ++i) for ( j = 0; j < Y; ++j) { *p2 = (elem_t)(100*i + j); assert( memory->array2[i][j] == *p2 ); ++p2; } return EXIT_SUCCESS; } 

Le problème est ce type** p2; est un pointeur sur un pointeur, cela n’a rien à voir avec les tableaux 2D.

Déclarez plutôt un pointeur sur un tableau 2D:

 type (*p2)[x][y]; 

Si vous n’aimez pas dé-référencer le tableau 2D en tant que (*p2)[i][j] , supprimez simplement la dimension la plus à l’intérieur de la déclaration:

 type (*p2)[y]; 

Vous pouvez maintenant dé-référencer le tableau 2D en p2[i][j] . Cette astuce fonctionne car p2[i] vous donne une arithmétique de pointeur basée sur le type pointé (un tableau d’éléments de type j), comme pour tout autre pointeur.


De plus, la conversion du pointeur vers (signé) int est obscure et dangereuse. Pour chaque cas dans le code où vous faites cela, conservez le type de caractère, calculez le décalage puis transmettez-le en (void*) . Exemple:

 p2 = (void*)(memory + p2_offset);