Manière correcte d’allouer et libérer des tableaux de pointeurs à des tableaux

Je veux créer un tableau de pointeurs sur des tableaux de 3 flotteurs. Quelle est la bonne façon de faire cela?

float *array1[SIZE]; // I think it is automatically allocated // OR float **array1 = calloc(SIZE, sizeof(float*)); free(array1); for (int i = 0; i < SIZE; i++) { array1[i] = (float[]){0,0,0}; // OR array1[i] = calloc(3, sizeof(float)); } 

Alors, comment pourrais-je libérer les données? Je suis presque sûr que je suis free(array1); ne fonctionnerait pas, donc je libérerais chaque pointeur dans le tableau puis libérerais le tableau, ou puisque j’ai alloué trois flottants, pourrais-je libérer chaque flottant, puis chaque tableau de 3 flottants, puis le tableau entier ???

En règle générale, pour chaque appel de malloc() ou calloc() vous devez effectuer un appel free() sur le pointeur renvoyé .

Si vous voulez un tableau à deux dimensions avec une taille connue au moment de la compilation, utilisez simplement un tableau à deux dimensions! float val[5][3] est parfaitement valide.

Si vous voulez un tableau à deux dimensions et que vous ne connaissez pas sa taille lors de la compilation, vous voudrez probablement utiliser un calloc () simple, à une seule dimension, et un getter approprié.

 #define ARR_COLUMNS 10 #define ARR_ROWS 10 float* arr = calloc (ARR_COLUMNS * ARR_ROWS, sizeof(float)); int get(float* arr, int x, int y) { if (x<0 || x>= ARR_COLUMNS) return 0; if (y<0 || y>= ARR_ROWS) return 0; return arr[ARR_COLUMNS*y+x]; } void set (int* arr, int x, int y, float val) { if (x<0 || x>= ARR_COLUMNS) return; if (y<0 || y>= ARR_ROWS) return; arr[ARR_COLUMNS*y+x] = val; } 

Bien sûr, remplacez les définitions par des variables appropriées.

Ce faisant, vous allez:

  • épargnez-vous coûteux alloue et libère
  • avoir une mémoire moins fragmentée
  • simplifiez vos appels realloc possibles
  • assurez-vous que les données sont mieux mises en cache et accessibles sans le problème commun du cache d’itération [x] [y] vs [y] [x].

Si vous connaissez la taille du tableau au moment de la compilation (et vous le savez, si SIZE est une constante au moment de la compilation), vous devez simplement déclarer un tableau à deux dimensions. Vous n’avez pas besoin de libérer cela du tout (et vous ne devez pas).

 float array1[SIZE][3]; 

Vous devez utiliser calloc et créer un tableau de pointeurs uniquement si les dimensions ne sont pas connues au moment de la compilation. Dans ce cas, il devrait y avoir un appel à free pour chaque appel à calloc . Et comme vous ne pouvez pas utiliser un tableau après l’avoir libéré, vous devez libérer les tableaux avant de libérer array1 .

 float **array1 = calloc(nrows, sizeof (float *)); for (int i=0; i < nrows; i++) array1[i] = calloc(3, sizeof(float)); // Use it... // Now free it for (int i=0; i < nrows; i++) free(array1[i]); free(array1); 

Edit: si vous ne réorganisez pas les pointeurs (pour sortinger les lignes sur place, par exemple), vous pouvez faire tout cela avec un seul calloc (et un appel à free par free suite):

 float (*array1)[3] = calloc(3*nrows, sizeof (float)); 

En effet, le nombre de colonnes est connu au moment de la compilation et c’est tout ce que l’arithmétique de pointeur doit connaître. Ensuite, vous pouvez écrire des choses comme array1[i][j] , et vous pouvez toujours passer autour de array1[i] comme s’il s’agissait d’un véritable pointeur sur une ligne. C est génial comme ça, profitez-en!

Je veux créer un tableau de pointeurs sur des tableaux de 3 flotteurs. Quelle est la bonne façon de faire cela?

Pourquoi voulez-vous un array of pointers to arrays ? Un array of arrays ne serait-il pas suffisant? (N’oubliez pas que les tableaux ressemblent déjà à des pointeurs, ils ne sont pas passés par valeur. L’adresse du premier élément est transmise lorsqu’un tableau est passé en tant qu’argument à une fonction).

 // stack allocation, no need to free float array[SIZE][3]; for (int i = 0; i < SIZE; i++) { // do something with array[i][0], array[i][1], array[i][2] } 

Alors, comment pourrais-je libérer les données?

Dans ce cas, vous ne le feriez pas, car les données sont allouées en stack (seront nettoyées automatiquement une fois hors de scope). Rappelez-vous que la règle de base est que pour chaque allocation de mémoire que vous effectuez, une mémoire libre correspondante est nécessaire. Donc, si vous allouez de la mémoire pour un tableau de flotteurs, comme dans

 float* arr = malloc(sizeof(float) * 3); // array of 3 floats 

Ensuite, il vous suffit d'appeler gratuitement sur le tableau que vous avez malloc'd , pas besoin de libérer les flotteurs individuels. Si vous effectuez une allocation nestede comme dans

 // array of length SIZE, consisting of float pointers float** arr = malloc(sizeof(float*) * SIZE); // allocate the array of 3 floats at each index for (int i = 0; i < SIZE; i++) arr[i] = malloc(sizeof(float) * 3); 

Ensuite, vous devrez effectuer un free pour chaque malloc , comme dans

 // free the individual arrays for (int i = 0; i < SIZE; i++) free(arr[i]); // free the array of arrays free(arr); 

La leçon à retenir ici est d'éviter toute allocation dynamic de tableaux. Tenez-vous-en avec les tableaux std::vector ou alloués par stack.