#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.