munmap_chunk(): недопустимый указатель при освобождении структуры в массиве

#arrays #c #pointers #struct

#массивы #c #указатели #структура

Вопрос:

Итак, я написал программу, в которой я должен перераспределять массив структур всякий раз, когда я хочу что-то добавить к нему. Но когда я пытаюсь освободить массив, я освобождаю каждый элемент по отдельности, но munmap_chunk(): invalid pointer в какой-то момент получаю a .

Вот полный код :

 #include <stdlib.h>
#include <string.h>

struct Date {
    int day;
    int month;
    int year;
};

struct Person {
    char *name;
    char *surname;
    struct Date birth;
};

struct Directory {
    int size;
    struct Person *array;
};

struct Date create_date() {
    struct Date date = {
            .day = 0,
            .month = 0,
            .year = 0
    };

    return date;
}

struct Directory create_directory() {
    struct Directory directory = {
            .size = 0,
            .array = NULL
    };

    return directory;
}

struct Person *create_person() {
    struct Person *person_ptr = (struct Person *) malloc(sizeof(struct Person));

    person_ptr->name = NULL;
    person_ptr->surname = NULL;

    return person_ptr;
}

void copy_date(struct Date *dest, struct Date *src) {
    dest->day = src->day;
    dest->month = src->month;
    dest->year = src->year;
}

void initialize_person(struct Person *person_ptr, char *name, char *surname, struct Date *birth) {
    if (name != NULL amp;amp; surname != NULL amp;amp; birth != NULL) {
        person_ptr->name = realloc((*person_ptr).name, (strlen(name) * sizeof(char))   1);
        strcpy(person_ptr->name, name);

        person_ptr->surname = realloc((*person_ptr).surname, (strlen(surname) * sizeof(char))   1);
        strcpy(person_ptr->surname, surname);

        copy_date(amp;person_ptr->birth, birth);
    }
}

void copy_person(struct Person *dest, struct Person *src) {
    dest->name = realloc((*dest).name, (strlen(src->name) * sizeof(char))   1);
    dest->surname = realloc((*dest).surname, (strlen(src->surname) * sizeof(char))   1);

    struct Date date = create_date();
    dest->birth = date;

    strcpy(dest->name, src->name);
    strcpy(dest->surname, src->surname);
    copy_date(amp;dest->birth, amp;src->birth);
}

int add_person(struct Directory *directory_ptr, const struct Person *new_person_ptr) {
    int return_code = 0;

    directory_ptr->size  ;
    directory_ptr->array = realloc(directory_ptr->array, (directory_ptr->size * sizeof(struct Person)));

    if (directory_ptr->array) {
        copy_person(amp;directory_ptr->array[directory_ptr->size - 1], (struct Person *) new_person_ptr);
    } else {
        return_code = 1;
    }

    return return_code;
}

int add_multiple_persons(struct Directory *directory_ptr, const struct Person **persons_ptr, int nb_persons) {
    for (int i = 0; i < nb_persons; i  ) {
        add_person(directory_ptr, (persons_ptr[i]));
    }

    return 0;
}

void destroy_person(struct Person *person_ptr) {
    free(person_ptr->name);
    person_ptr->name = NULL;

    free(person_ptr->surname);
    person_ptr->surname = NULL;

    free(person_ptr);
    person_ptr = NULL;
}

void destroy_directory(struct Directory *directory_ptr) {
    if (directory_ptr->array) {
        for (int i = 0; i < directory_ptr->size; i  ) {
            destroy_person(amp;directory_ptr->array[i]);
        }
        directory_ptr->array = NULL;
        directory_ptr->size = 0;
    }
}

int main(void) {
    struct Directory directory = create_directory();
    struct Person *person1 = create_person();
    struct Person *person2 = create_person();
    struct Person *person3 = create_person();
    struct Date date = {
            .day = 17,
            .month = 04,
            .year = 1999};

    initialize_person(person1, "Marcel", "Juan", amp;date);
    initialize_person(person2, "Albin", "Michel", amp;date);
    initialize_person(person3, "Suzerain", "Bernard", amp;date);

    const struct Person *array[] = {
            person1,
            person2,
            person3
    };

    add_multiple_persons(amp;directory, array, 3);
    destroy_person(person1);
    destroy_person(person2);
    destroy_person(person3);
    destroy_directory(amp;directory);

    return 0;
}
  

Я сталкиваюсь с этой ошибкой уже больше недели, и она продолжает меня беспокоить.
Как я могу это исправить?

Комментарии:

1. Не могли бы вы уточнить, после выполнения какой строки появляется ошибка?

2. Ошибка возникает в строке 109, после вызова destroy_person() из destroy_directory()

Ответ №1:

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

     void destroy_directory(struct Directory *directory_ptr) {
       if (directory_ptr->array) {

           free(directory_ptr->array); //<==== Here

           directory_ptr->array = NULL;
           directory_ptr->size = 0;
       }
    }
  

Комментарии:

1. You cannot use realloc with a string that was not allocated via malloc. So in the initialization function you should use malloc instead of realloc . Это неверно. Если первый аргумент равен NULL , realloc ведет себя точно так же, как malloc .

2. @emi Вы правы, я думал, что OP передал литеральную строку, объявленную в main в realloc, но это не так. Спасибо, что указали на это.

3. Поддержано после редактирования: это понятнее, чем у меня. @dspr Он обнуляется create_person при первоначальном объявлении.

Ответ №2:

person_ptr является частью памяти, выделенной в directory_ptr->array . Вам нужно удалить эту строку.

Как правило, ответственность за память одинакова при выделении и при освобождении. В вашем коде person владельцем является array внутренняя directory_ptr часть, которая выделяется add_person . Несмотря на свое название, это directory менеджер, поэтому освобождение его памяти должно выполняться только на directory destroyer.