функция для очистки Mallo c, и сделать указатель на ноль - PullRequest
1 голос
/ 07 марта 2020

в моем последнем вопросе , я спросил, как использовать функцию для освобождения массива mallo c, я хотел улучшить свой код, чтобы функция не просто освобождала память но также установит указатель на NULL после завершения очистки. Также я хочу, чтобы одна функция выполняла и настройку, и очистку, в зависимости от команды , которую я передаю, это то, что я сделал до сих пор:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint-gcc.h>

char **set_arr(int number, char *command);
int command_read(char *command);
void clear_arr(char *arr[], int size);

char set[] = "set";
char clear[] = "clear";

int main() {
    int num = // get number from user;
    char** my_arr = NULL;
    my_arr = set_arr(num, set);
    // so far the code works as excepted
    set_arr((size_t)&my_arr, clear);
    return 0;
}

int command_read(char *command) {
    if (strcmp(command, set) == 0)
        return 'S';
    if (strcmp(command, clear) == 0)
        return 'C';
}

char **set_arr(int number, char *command) {
    static char **arr = NULL;
    static int size;
    switch (command_read(command)) {
      case 'S':
        size = (int)number;
        arr = malloc((size + 1) * sizeof(char *));
        for (int i = 0; i <= size; i++) {
            arr[i] = NULL;
            if (i == size)
                break;
            arr[i] = malloc((string_len) * sizeof(char));
        }
        break;
      case 'C':
        clear_arr(arr, size);
        free(arr);
        uintptr_t value = number;
        uint64_t *temp = (void *)value;
        *temp = 0x0;
        break;
    }
    return arr;
}

void clear_arr(char *arr[], int size) {
    for (int i = 0; i < size; i++) {
        free(arr[i]);
        arr[i] = NULL;
    }    
}

Я знаю что есть лучшие методы для очистки (и выделения памяти?), но мой основной вопрос заключается в том, освободил ли я всю память, выделенную для массива, и после очистки правильно ли установлен указатель my_arr на NULL?

Ответы [ 2 ]

3 голосов
/ 07 марта 2020

Написание обобщенной c функции для достижения вашей цели в стандарте C невозможно, поскольку указатели на разные типы объектов могут иметь различное представление, поэтому вы не можете передать адрес указателя и ожидать, что функция его обработает. в общем случае c.

Однако это положение в стандарте C не используется в большинстве современных систем сегодня. В частности, стандарт POSIX предусматривает, что все указатели имеют одинаковое представление. Следовательно, ваша функция generi c может работать в этих системах с некоторыми мерами предосторожности, чтобы избежать предупреждений компиляции:

// free an array of allocated things
void free_array(void ***p, size_t count) {
    void **array = *p;
    for (size_t i = 0; i < count; i++) {
        free(array[i]);
        array[i] = NULL; // for safety
    }
    free(array);
    *p = NULL;
}
// deal with the non portable conversion with macros
#define FREE_ARRAY(p, n)   free_array((void ***)(void *)&(p), n)

// allocate an array of pointers to allocated things of size `size`.
// return a pointer to the array or `NULL` if any allocation failed
void **malloc_array(size_t count, size_t size) {
    void **array = malloc(count * sizeof(*array));
    if (array) {
        for (size_t i = 0; i < count; i++) {
            array[i] = calloc(size, 1);  // allocate and initialize to all bits zero
            if (array[i] == NULL) {
                while (i-- > 0) {
                    free(array[i]);
                    array[i] = NULL;
                }
                return NULL;
            }
        }
    }
    return array;
}
#define MALLOC_ARRAY(n, type)  ((type **)(void *)malloc_array(n, sizeof(type)))
#define MALLOC_2D_ARRAY(n1, n2, type)  ((type **)(void *)malloc_array(n1, (n2) * sizeof(type)))

Передача команды в виде строки очень неэффективна. Вы должны использовать int или enum для команды, но вы можете использовать вышеупомянутые макросы и код в вашей программе следующим образом:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint-gcc.h>

int main() {
    int string_len = 100;
    int num = 10; // get number from user;
    char **my_arr = MALLOC_2D_ARRAY(num, string_len, char);
    FREE_ARRAY(my_arr, num);
    return 0;
}
0 голосов
/ 07 марта 2020

Если я понимаю ваш вопрос: у вас есть массив char* arr[], который вы хотите полностью освободить

Я думаю, если вы хотите освободить его, вы должны сделать

int i = 0;
while (arr[i])
{
    free(arr[i]);
    arr[i] = NULL;
}
free(arr);
arr = NULL;

если вы использовали неправильный указатель char ** arr, вы также должны его освободить

Lmk, если этот ответ помогает

Причина установки указателя в NULL:

с использованием свободной функции на нулевом указателе ничего не делает ... (Это предотвращает дальнейшие сбои в вашем коде)

/! \ Но с помощью функции free для указателя, который уже был освобожден ранее (и не установлен в ноль) взломает sh вашу программу

Вызов бесплатного метода для указателя, который не был заблокирован, также вызовет sh вашу программу

Я не знаю, есть ли функция чтобы узнать, был ли указан указатель c на раздел кучи памяти

Также необходимо отметить, что метод Mallo c берет часть страницы памяти из раздела кучи и флаг как выделено

* 10 28 * Свободный метод просто UNflag it

Свободный метод никогда не заменяет биты в памяти на 0, он оставляет все как есть Это похоже на удаление файла на вашем рабочем столе он не заменяется на 0, чтобы стереть его, просто отметьте его как неиспользованный

...