Can you please tell me if you need to free the memory block pointed to by maze in the generateMаze() method using the free() function. I use the cleanMemory() method to free up memory, but is it necessary? If maze is a local variable, then the memory will be allocated on the stack and will the memory be cleared when exiting the function? A lot of pointers in the program, I do not understand where it is necessary, and where it is not necessary to use free() . Please clarify this moment.

 #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <windows.h> #include <time.h> #include "functions.h" //цілочисленна змінна для збереження кількості напрямів (вправо, вліво, вгору, вниз) int amountOfDirections = 4; //ітераційні змінні для для проходження в циклі по елементах матриці int i, j; void printWarningAndExit() { puts("Memory allocation failure"); exit(1); } void printMaze(int **maze, int width, int height) { printf("\n\n\n"); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (maze[i][j] == 0) /* встановлення кольору тексту в консолі кожному кольору відповідає числове значення, яке передається функції другим аргументом */ SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12); else if (maze[i][j] == 2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14); else if (maze[i][j] == 5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 28); else { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 26); } printf("%2d ", maze[i][j]); } printf("\n"); //повернення кольору тексту до білого на чорному фоні після виведення матриці в консоль SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); } } void swap(int *a, int *b) { int temp; //записуємо значення, яке зберігається за адресою, на яку вказує а //у змінну temp temp = *a; //записуємо за адресою, на яку вказує вказівник а, значення, //котре міститься за адресою, на яку вказує вказівник b *a = *b; //записуємо за адресою, на яку вказує вказівник b, значення, //котре зберігається у змінній temp --> "старе" значення *a *b = temp; } void shuffle(int *array, int size) { //призупиняємо роботу програми на 1150 ms Sleep(1150); /* встановлення в якості бази генератора випадкових чисел поточний час цей прийом використовується для того, щоб при різних запусках генератора була кожен раз різна база генератора і відповідно різні випадкові значення через те, що srand() буде оновлювати базу генератора кожну секунду, а функція shuffle() буде викликатися КІЛЬКА РАЗ в секунду, використовуємо sleep() на 1 секунду щоб гарантувати різні випадкові значення кожен раз при виклику rand() в shuffle() */ srand(time(NULL)); //ітеруємося від кінця масиву до його початку for (i = size - 1; i > 0; i--) { //отримуємо випадкове значення від 0 до i включно j = rand() % (i + 1); /* міняємо місцями елемент під відповідним до поточної ітерації індексом та елемент під випадковим індексом наприклад маємо масив [1, 2, 3, 4] розглядаємо елемент з індексом 2 --> 3 генеруємо випадкове значення від 0 до 2 включно тобто можемо переставити елемент з будь-яким зліва чи залишити елемент на своєму місці */ swap(&array[i], &array[j]); } } int* generateRandomDirections() { //створюємо 4-елементний одномірний масив int *randoms; if ((randoms = (int*)calloc(amountOfDirections, sizeof(int))) == 0) { printWarningAndExit(); } //заповнюємо його значеннями [1, 2, 3, 4] for (int i = 0; i < amountOfDirections; i++) randoms[i] = i + 1; //перемішуємо їх shuffle(randoms, amountOfDirections); //повертаємо масив return randoms; } void recursion(int **maze, int width, int height, int raw, int col) { printf("."); //отримуємо масив з 4 значень {1, 2, 3, 4}, розташованих у ньому у випадковому порядку int* randDirections = generateRandomDirections(); //аналізуємо кожен напрямок for (i = 0; i < amountOfDirections; i++) { switch (randDirections[i]) { case 1: //UP if (raw - 2 <= 0) { /* якщо немає елемента на 2 рядка вище над поточним або ж він лежить на верхньому "кордоні" лабіринту (що недопустимо, адже при генерації утвориться кілька входів)... */ continue; } //якщо елемент, котрий на 2 рядка вище над поточним, рівний 1(стіна) if (maze[raw - 2][col] == 1) { //то заповнюємо нулями 2 ячейки лабіринту вертикально вгору від поточної maze[raw - 2][col] = 0; maze[raw - 1][col] = 0; //викликаємо цю ж функцію для елементу, котрий на 2 рядка вище від поточного //(тепер він стає поточним) recursion(maze, width, height, raw - 2, col); } break; case 2: //Right /* якщо немає елемента на 2 стопця правіше від поточного або ж він лежить на правому "кордоні" лабіринту (що недопустимо, адже при генерації утвориться кілька входів), або ж елемент знаходиться на верхньому "кордоні"(наприклад, якщо розглядаємо вхід, то ми не можемо зробити коридор вправо від входу)... */ if ((col + 2) >= width - 1 || raw == 0) { continue; } //якщо елемент, котрий на 2 стопвця правіше від поточного, рівний 1(стіна) if (maze[raw][col + 2] == 1) { //то заповнюємо нулями 2 ячейки лабіринту горизонтально вправо від поточної maze[raw][col + 2] = 0; maze[raw][col + 1] = 0; //викликаємо цю ж функцію для елементу, котрий на 2 стопці правіше від поточного //(тепер він стає поточним) recursion(maze, width, height, raw, col + 2); } break; case 3: //Down /* якщо немає елемента на 2 рядка нижче під поточним або ж він лежить на нижньому "кордоні" лабіринту (недопустимо, утвориться кілька виходів після різних рекурсивних викликів)... */ if ((raw + 2) >= height - 1) continue; //якщо елемент, котрий на 2 рядка нижче під поточним, рівний 1(стіна) if (maze[raw + 2][col] == 1) { //то заповнюємо нулями 2 ячейки лабіринту вертикально вниз від поточної maze[raw + 2][col] = 0; maze[raw + 1][col] = 0; //викликаємо цю ж функцію для елементу, котрий на 2 рядка нижче від поточного //(тепер він стає поточним) recursion(maze, width, height, raw + 2, col); } break; case 4: //Left /* якщо немає елемента на 2 стопця лівіше від поточного або ж він лежить на лівому "кордоні" лабіринту (що недопустимо, адже при генерації утвориться кілька входів), або ж елемент знаходиться на верхньому "кордоні"(наприклад, якщо розглядаємо вхід, то ми не можемо зробити коридор вліво від входу)... */ if ((col - 2) <= 0 || raw == 0) continue; //якщо елемент, котрий на 2 стопвця лівіше від поточного, рівний 1(стіна) if (maze[raw][col - 2] == 1) { //то заповнюємо нулями 2 ячейки лабіринту горизонтально вліво від поточної maze[raw][col - 2] = 0; maze[raw][col - 1] = 0; //викликаємо цю ж функцію для елементу, котрий на 2 стопці лівіше від поточного //(тепер він стає поточним) recursion(maze, width, height, raw, col - 2); } break; } } //ітеруємося елементах з парними індексами(за рахунок того, що будуємо коридори по 2 клітинки, //побудова коридору відносно елементу з непарними індексами призведе до злиття коридорів //і лабіринт буде мати широкі проходи), причому не враховуємо перші 2 стовпця, останній стовпець (завжди будуть стіни), , //рядок із входом(все одно неможливо буде побудувати ще один коридор відносно входу), рядок нижче(бо непарний індекс), //останній рядок(всі одиниці, поки не згенеруємо вихід) for (i = 2; i < height - 1; i += 2) { for (j = 2; j < width - 1; j += 2) { //якщо елемент 0(прохід) і можно від нього побудувати коридор if (maze[i][j] == 0 && !deadend(maze, width, height, i, j)) { //викликаємо для нього функцію recursion(maze, width, height, i, j); //перериваємо ітерації по матриці break; } } } } void showInfo() { printf("\n"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 46); puts(" "); puts(" ## ## ## ################## ########## "); puts(" # # # # # # # # "); puts(" # # # # # # # # "); puts(" # # # # # # # # "); puts(" # ## # # # # # "); puts(" # # ############ # ########## "); puts(" # # # # # # "); puts(" # # # # # # "); puts(" # # # # # # "); puts(" # # # # ################## ########## "); puts(" "); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12); puts(" --------------------------------------------------"); puts(" | HELLO |"); puts(" | |"); puts(" | press G to generate a maze |"); puts(" | press E to exit from game |"); puts(" | |"); puts(" | |"); puts(" --------------------------------------------------"); printf("\n"); } int executeRequest() { showInfo(); char answer; do { answer = _getch(); if (answer == 'G') { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 121); puts(" "); puts(" # ##### ## ### # ## # ####### "); puts(" # # # # # # # # # # # # "); puts(" # # # ###### # # # # # # # ### "); puts(" # # # # # # # # # # # # # ### ### ### "); puts(" ###### ##### # # ### # # ## ####### ### ### ### "); puts(" "); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); animateLoading(); printf("\n"); return 1; } else if (answer == 'E') { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 31); puts(" "); puts(" ####### ## ## ## ##### ##### # # ##### ##### "); puts(" # # # # # # # # # # # # # # # "); puts(" # ### ###### # ## # ##### # # # # ##### ##### "); puts(" # # # # # # # # # # # # # # "); puts(" ####### # # # # ##### ##### ## ##### # # "); puts(" "); printf("\n"); return 0; } else { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 71); puts(" "); puts(" ##### ##### ##### ##### ##### "); puts(" # # # # # # # # # "); puts(" ##### ##### ##### # # ##### "); puts(" # # # # # # # # # "); puts(" ##### # # # # ##### # # "); puts(" "); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); printf("\n"); } } while (1); } void generateMaze() { int width, height; initDimensions(&width, &height); int** maze = provideMemory(width, height); initOnes(maze, width, height); int entranceX = initEntrance(maze, width, height); recursion(maze, width, height, 0, entranceX); generateRandExit(maze, width, height); printMaze(maze, width, height); char answer; while (1) { puts("Enter 's' to solve maze : "); answer = _getch(); if (answer == 's') { solveMaze(maze, width, height, 0, entranceX, 3); break; } } cleanMemory(maze, height); } void initDimensions(int* widthPointer, int* heightPointer) { int askCaseWrongInput = 1; do { puts("Enter the width of the maze(positive integer greater than 5)"); scanf_s("%u", widthPointer); puts("Enter the height of the maze(positive integer greater than 5)"); scanf_s("%u", heightPointer); if (*widthPointer > 5 && *heightPointer > 5) { break; } else { puts("\nEnter the correct dimension of the maze, please\n"); } } while (askCaseWrongInput); } int** provideMemory(int width, int height) { int **maze; if ((maze = (int**)calloc(height, sizeof(int*))) == 0) { printWarningAndExit(); } for (i = 0; i < height; i++) { if ((maze[i] = (int*)calloc(width, sizeof(int))) == 0) { printWarningAndExit(); } } return maze; } void initOnes(int** maze, int width, int height) { for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { maze[i][j] = 1; } } } int initEntrance(int** maze, int width, int height) { int yrandomEntrance; //оновлення бази генератора випадкових чисел кожну секунду srand(time(NULL)); //генеруємо випадковий вхід, причому розглядаємо тільки парні індекси //не враховуючи крайній лівий і крайній правий елементи yrandomEntrance = 2 * (1 + (rand() % ((width - 2) / 2))); //initialize the entrance by 0 maze[0][yrandomEntrance] = 0; return yrandomEntrance; } void runGame() { while (executeRequest()) { system("cls"); generateMaze(); } } void cleanMemory(int **matrix, int height) { for (i = 0; i < height; i++) free(matrix[i]); free(matrix); } void animateLoading() { for (i = 0; i < 10; i++) { Sleep(200); printf("."); } printf("\n"); } //todo addresses int deadend(int** maze, int width, int height, int raw, int col) { int a = 0; //див. функцію recursion() //умови if raw == 0 не перевіряємо, адже у функції recursion() //нульові індекси не будуть розглядатися при ітеруванні по елементах матриці if (raw - 2 <= 0 || maze[raw - 2][col] == 0) a++; if ((col + 2) >= width - 1 || maze[raw][col + 2] == 0) a++; if ((raw + 2) >= height - 1 || maze[raw + 2][col] == 0) a++; if ((col - 2) <= 0 || maze[raw][col - 2] == 0) a++; if (a == 4) return 1; else return 0; } void generateRandExit(int** maze, int width, int height) { //генеруємо вихід(будь-яка ячейка від індексу 2 до передостаннього індексу) int randomExit = 2 + rand() % (width - 3); maze[height - 1][randomExit] = 0; //з'єднуємо вихід з лабіринтом //якщо висота представляє собою непарне число, то передостаннім рядком будуть 1 if (height % 2 == 1) { //змінюємо елемент на рядок вище від виходу на 0 maze[height - 2][randomExit] = 0; //піднімаємося ще на рядок, якщо і там 1 то міняємо на 0 if (maze[height - 3][randomExit] == 1) { maze[height - 3][randomExit] = 0; } } //якщо висота представляє собою парне число, то передостаннім рядком можуть бути нулі чи одиниці else { if (maze[height - 2][randomExit] == 1) { maze[height - 2][randomExit] = 0; } } } //1 - up //2 - left //3 - down //4 - right void solveMaze(int **maze, int width, int height, int raw, int col, int flag) { while (1) { system("cls"); maze[raw][col] = 5; printMaze(maze, width, height); maze[raw][col] = 2; Sleep(200); if (raw == height - 1) break; switch (flag) { case 1: if (maze[raw][col - 1] != 1) { flag = 2; col--; } else if (maze[raw - 1][col] != 1) { flag = 1; raw--; } else if (maze[raw][col + 1] != 1) { flag = 4; col++; } else { flag = 3; raw++; } break; case 2: if (maze[raw + 1][col] != 1) { flag = 3; raw++; } else if (maze[raw][col - 1] != 1) { flag = 2; col--; } else if (maze[raw - 1][col] != 1) { flag = 1; raw--; } else { flag = 4; col++; } break; case 3: if (maze[raw][col + 1] != 1) { flag = 4; col++; } else if (maze[raw + 1][col] != 1) { flag = 3; raw++; } else if (maze[raw][col - 1] != 1) { flag = 2; col--; } else { flag = 1; raw--; } break; case 4: if (maze[raw - 1][col] != 1) { flag = 1; raw--; } else if (maze[raw][col + 1] != 1) { flag = 4; col++; } else if (maze[raw + 1][col] != 1) { flag = 3; raw++; } else { flag = 2; col--; } break; } } printf("PATH WAS FOUND"); } 
  • What is it local if you have to manually allocate memory to it? You must free all the memory you requested. - vp_arth

1 answer 1

As I understand it from the code, you need to release the maze . since maze points to a dynamic memory area which contains a pointer that points to another memory area which contains arrays. That is, it turns out the matrix. But like you do it.

int** maze; This is a static variable and the memory for it will be released when it goes out of scope. But! it indicates the dynamic memory area to be freed.

  • Thank you very much. Very helpful. Tell me more, is there a randDirections pointer in the recursion () method, do you also need to apply free () to it? - Andrey Rafalsky
  • @AndreyRafalsky, the life cycle of each calloc / malloc should eventually end with a call to free - vp_arth
  • thanks, figured out - Andrey Rafalsky