Hello, help solve the problem. The problem is to clean up the multidimensional array before exiting in case of not allocating memory. I already asked a similar question about cleaning before leaving, many recommend not to rely on the OS, but to clean it myself, but I have a problem. It is necessary to clear the entire multidimensional array, but I do not have enough "mind" to implement cleaning. If in the first and in the second case - you can think and implement cleaning, then in the third it is difficult. In C_ONE and C_TWO there can be, for example, any number, this is just an example.

#include <stdio.h> #include <stdlib.h> #include <string.h> #define C_ONE 2 #define C_TWO 2 int main(void) { char ***test = NULL; for (unsigned char i = 0; i < C_ONE; i++) { test = (char ***) realloc((i + 1) * sizeof(char **)); if (test == NULL) { // тут всё просто if (i > 0) { for (unsigned char j = 0; j < i; j++) { for (unsigned char k = 0; k < C_TWO; k++) free(*(*(test + j) + k)); free(*(test + j)); } free(test); } exit(-1); } *(test + i) = (char **) malloc(C_TWO * sizeof(char *)); if (*(test + i) == NULL) { /** * Хорошо, а тут как "всё" очистить? **/ exit(-1); } for (unsigned char m = 0; m < C_TWO; m++) { *(*(test + i) + m) = (char *) malloc((1 + 1) * sizeof(char)); if (*(*(test + i) + 0) == NULL) { /** * Если во втором случае можно подумать и написать, * тогда в этом уже сложно. **/ exit(-1); } strcpy(*(*(test + i) + m), "W"); } } // если всё успешно, то очистка, как и в первом случае. for (unsigned char m = 0; m < C_ONE; m++) { for (unsigned char o = 0; o < C_TWO; o++) free(*(*(test + m) + o)); free(*(test + m)); } free(test); return 0; } 
  • one
    What does cleaning mean? If this is the release of memory, then you can not worry, all the allocated memory after the application is completed will return to the system. - tilin
  • @tilin "" "I already asked a similar question about cleaning before leaving, many recommend not to rely on the OS, but to clean it yourself, " "" - user245984
  • I already wrote that you need to clean up at least when you run the program under the profiler, so as not to litter the leak log. - ߊߚߤߘ
  • @Arhad I clean up before exiting, but if nothing is selected during the selection, the program crashes. I am trying to control this as shown above. Cleaning is not a problem, but when it comes in like this, it is difficult to clean, and even in a cycle. - user245984
  • one
    To begin with, you are inconsistently allocating and freeing memory. Judging by the pointers, you want an array of arrays of arrays, but you allocate memory as a single-level solid piece. And release it all the same as the originally conceived array of arrays of arrays. - ߊߚߤߘ

1 answer 1

Let's start with the fact that for some reason you are trying to clear all levels of the array even if it fails to select the top level.

Secondly, the success of the allocation of memory must be checked at the very beginning, in order to abort the work in case of failure.

Now we proceed to the correction. To begin, let us use the principle of modularity and make the allocation and release of memory in separate functions:

 char*** allocate(); void deallocate(char** array); 

We realize memory allocation:

 // Размерности массива #define X_COUNT 5 #define Y_COUNT 2 #define Z_COUNT 8 char*** allocate() { // Пытаемся выделить верхний уровень char*** const array = (char***)malloc(X_COUNT * sizeof(char**)); // Если выделение успешно, заполняем второй уровень, иначе прерываемся if(array) { // Заполняем массив, пока не дойдём до конца, либо не поймаем ошибку. // И да, я считаю трюки типа while(true) + break вводящими в заблуждение, // так что воспользуемся флагом. bool metError = false; size_t xId, yId; for(xId = 0; xId < X_COUNT && !metError; ++xId) { // Пытаемся выделить массив второй размерности array[xId] = (char**)malloc(Y_COUNT * sizeof(char*)); if(array[xId]) { for(yId = 0; yId < Y_COUNT && !metError; ++yId) { // Пытаемся выделить обнулённый массив третьей размерности array[xId][yId] = calloc(Z_COUNT, sizeof(char)); if(!array[xId][yId]) metError = true; } } else metError = true; } // Если встретили ошибку — откатываем всё, что успели выделить, // включая первый уровень. // // Собственно, для определения позиции окончания успешного заполнения // xId и yId и были вынесены наружу, чтобы стать доступными отсюда. if(metError) { // Первые xId строк массива были успешно выделены целиком for(size_t x = 0; x < xId; ++x) { for(size_t y = 0; y < Y_COUNT; ++y) free(array[x][y]); free(array[x]); } // Последняя же выделенная строка оборвалась на выделении yId-го // столбца for(size_t y = 0; y < yId; ++y) free(array[xId][y]); free(array[xId]); free(array); return NULL; } else return array; } else return NULL; } 

Releasing is much easier. No checks are required, just pass through both levels.

 void deallocate(char*** array) { for(xId = 0; xId < X_COUNT; ++xId) { for(yId = 0; yId < Y_COUNT; ++yId) free(array[xId][yId]); free(array[xId]); } free(array); } 
  • It's clear. but I have a problem with a three-dimensional array. And why did you decide that judging by C_ONE and C_TWO - this is a selection for two-dimensional? here is a simple form of the same as shown in my question in char test[2][2][3] = {{{'1', '2', '\0'}, {'3', '4', '\0'}}, {{'5', '6', '\0'}, {'7', '8', '\0'}}}; that is, the output would be fprintf(stdout, "%s\n", test[0][0]); // 12 fprintf(stdout, "%s\n", test[0][0]); // 12 , but this is not the case, allocating memory for the latest level test[1][1] , for example, the memory may not be allocated, which means you need to clear test[1][0] , then test[1] , then test[0][1] , then test[0][0] and then test[0] - user245984
  • that is, you need to clear all that remains of test[1][1] or of the array for which memory is not allocated. C_ONE and C_TWO can contain any number, 2 is an example, therefore it is necessary that the program itself know that you need to clear everything that was allocated to test[1][1] , for example - user245984
  • @ast, fixed the three-dimensional case. Also, if C_ONE and C_TWO are not dimensions, then what do they do in terms of determining the size of allocated memory for malloc ? - ߊߚߤߘ
  • C_ONE and C_TWO are like an example, thank you very much for the answer. Now I will try to disassemble and insert into my code) - user245984
  • one
    @ Dmitriy Evgenievich Kholichev, у вас это точно массив - yes, the so-called jagged array. выделить его одним блоком agree, it would be possible to limit the creation of two large arrays (the actual data of the type char and the char* pointers at intermediate levels). But my task was to fix exactly the existing code (so as not to confuse the questioner). However, you can publish your thoughts with a separate answer (and collect pros for it). - ߊߚߤߘ