realloc 收缩失败
realloc fails on shrink
我不确定我是否在这里遗漏了什么,但是当我尝试收缩动态结构数组时,realloc() 因大小无效而失败。我将代码中的非必要功能修剪为 post:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char const file_name[] = "animals.dat";
typedef enum {
false, true } bool;
typedef struct {
char month;
char day;
short year;
} date;
typedef struct {
bool parvo_vacc;
bool fip_vacc;
bool rabies_vacc;
bool has_mc;
bool worm_vacc;
} md_history;
typedef struct {
int id;
char age;
char name[25];
char description[50];
md_history medical;
date intake_date;
date adopt_date;
} animal;
void lookup(animal* list, int size);
int compare(const void* this, const void* that);
void sort(animal* list, int size);
//this brings the new name back with it, since it isnt saved correctly
//in the new animal
animal* add(char* name);
void del(animal* list, int size);
void print_results(animal** results, int size);
void print_animal(animal* print);
void swap(animal* this, animal* that);
int main(int argc, char **argv)
{
FILE* readfile = fopen(file_name, "r");
if (readfile == NULL)
{
printf("Error file not found: %s\n", file_name);
}
//read data using fread(), keeping track of the number
//of bytes missed
int num_animals = 0;
fread(&num_animals, sizeof(int), 1, readfile);
animal* animal_list = (animal*) calloc(num_animals, sizeof(animal));
int errnum = num_animals - (fread(animal_list,
sizeof(animal), num_animals, readfile));
if (errnum > 0)
{
printf("Read encountered %d errors", errnum);
}
fclose(readfile);
char c;
char* name = malloc(sizeof(char) * 25);
//switch statements dont allow declarations for whatever reason
int x;
while(c != 'q')
{
printf("Options: (l)ookup (s)ort (a)dd (d)elete (p)rint (q)uit (e)dit\n");
scanf(" %c", &c);
switch (c)
{
case 'l':
lookup(animal_list, num_animals);
break;
case 's':
sort(animal_list, num_animals);
break;
case 'p':
for (x = 0; x < num_animals; x++)
{
print_animal(&animal_list[x]);
}
break;
case 'a':
//after dealing with lots of iostream errors trying to
//set the name field in add(), i decided to just return
//the new name to here and strcpy it
animal_list = realloc(animal_list, sizeof(animal) * (num_animals + 1));
swap(&animal_list[num_animals], add(name));
strcpy(animal_list[num_animals].name, name);
num_animals++;
//memory leak here, since switch statements dont allow
//declarations, i cant save the new animal pointer to a temp
//var so it can be deleted
break;
case 'd':
del(animal_list, num_animals);
num_animals--;
break;
}
}
return 0;
}
void swap(animal* this, animal* that)
{
animal temp;
temp.id = this->id;
strcpy(temp.name, this->name);
temp.age = this->age;
strcpy(temp.description, this->description);
temp.medical.fip_vacc = this->medical.fip_vacc;
temp.medical.has_mc = this->medical.has_mc;
temp.medical.parvo_vacc = this->medical.parvo_vacc;
temp.medical.rabies_vacc = this->medical.rabies_vacc;
temp.medical.worm_vacc = this->medical.worm_vacc;
temp.intake_date.day = this->intake_date.day;
temp.intake_date.month = this->intake_date.month;
temp.intake_date.year = this->intake_date.year;
temp.adopt_date.day = this->adopt_date.day;
temp.adopt_date.month = this->adopt_date.month;
temp.adopt_date.year = this->adopt_date.year;
this->id = that->id;
strcpy(this->name, that->name);
this->age = that->age;
strcpy(this->description, that->description);
this->medical.fip_vacc = that->medical.fip_vacc;
this->medical.has_mc = that->medical.has_mc;
this->medical.parvo_vacc = that->medical.parvo_vacc;
this->medical.rabies_vacc = that->medical.rabies_vacc;
this->medical.worm_vacc = that->medical.worm_vacc;
this->intake_date.day = that->intake_date.day;
this->intake_date.month = that->intake_date.month;
this->intake_date.year = that->intake_date.year;
this->adopt_date.day = that->adopt_date.day;
this->adopt_date.month = that->adopt_date.month;
this->adopt_date.year = that->adopt_date.year;
that->id = temp.id;
strcpy(that->name, temp.name);
that->age = temp.age;
strcpy(that->description, temp.description);
that->medical.fip_vacc = temp.medical.fip_vacc;
that->medical.has_mc = temp.medical.has_mc;
that->medical.parvo_vacc = temp.medical.parvo_vacc;
that->medical.rabies_vacc = temp.medical.rabies_vacc;
that->medical.worm_vacc = temp.medical.worm_vacc;
that->intake_date.day = temp.intake_date.day;
that->intake_date.month = temp.intake_date.month;
that->intake_date.year = temp.intake_date.year;
that->adopt_date.day = temp.adopt_date.day;
that->adopt_date.month = temp.adopt_date.month;
that->adopt_date.year = temp.adopt_date.year;
}
void del(animal* list, int size)
{
printf("Delete by: (n)ame (i)d\n");
char c;
while (getchar() != '\n');
scanf("%c", &c);
animal* to_delete = NULL;
if (c == 'n')
{
printf("Enter name to delete: ");
char to_search[25];
while (getchar() != '\n');
scanf(" %s", to_search);
int x;
for (x = 0; x < size; x++)
{
if (strcmp(to_search, list[x].name) == 0)
{
to_delete = &list[x];
}
}
}
if (c == 'i')
{
printf("Enter ID to delete: ");
int to_search;
while (getchar() != '\n');
scanf("%d", &to_search);
int x;
for (x = 0; x < size; x++)
{
if (to_search == list[x].id)
{
to_delete = &list[x];
}
}
}
swap(to_delete, &list[size);
list = realloc(list, sizeof(animal) * (size - 1)); //fails right here
}
我是否错误地缩小了数组?我在这里很困惑
编辑:我知道 realloc() 失败了,因为它做得非常好并中止,给出了这条消息:
*** Error in `./final': realloc(): invalid next size: 0x0000000000c11250 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x77725)[0x7f6ae72ba725]
/lib/x86_64-linux-gnu/libc.so.6(+0x82bfa)[0x7f6ae72c5bfa]
/lib/x86_64-linux-gnu/libc.so.6(+0x85179)[0x7f6ae72c8179]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7f6ae72c6e6f]
./final[0x401d3e]
./final[0x400b82]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f6ae7263830]
./final[0x400849]
======= Memory map: ========
00400000-00403000 r-xp 00000000 08:01 3146140 /home/destrovel/cppwork/final
00602000-00603000 r--p 00002000 08:01 3146140 /home/destrovel/cppwork/final
00603000-00604000 rw-p 00003000 08:01 3146140 /home/destrovel/cppwork/final
00c10000-00c31000 rw-p 00000000 00:00 0 [heap]
7f6ae0000000-7f6ae0021000 rw-p 00000000 00:00 0
7f6ae0021000-7f6ae4000000 ---p 00000000 00:00 0
7f6ae702d000-7f6ae7043000 r-xp 00000000 08:01 1069105 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6ae7043000-7f6ae7242000 ---p 00016000 08:01 1069105 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6ae7242000-7f6ae7243000 rw-p 00015000 08:01 1069105 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6ae7243000-7f6ae7403000 r-xp 00000000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7403000-7f6ae7602000 ---p 001c0000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7602000-7f6ae7606000 r--p 001bf000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7606000-7f6ae7608000 rw-p 001c3000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7608000-7f6ae760c000 rw-p 00000000 00:00 0
7f6ae760c000-7f6ae7632000 r-xp 00000000 08:01 1049970 /lib/x86_64-linux-gnu/ld-2.23.so
7f6ae77f9000-7f6ae77fc000 rw-p 00000000 00:00 0
7f6ae782e000-7f6ae7831000 rw-p 00000000 00:00 0
7f6ae7831000-7f6ae7832000 r--p 00025000 08:01 1049970 /lib/x86_64-linux-gnu/ld-2.23.so
7f6ae7832000-7f6ae7833000 rw-p 00026000 08:01 1049970 /lib/x86_64-linux-gnu/ld-2.23.so
7f6ae7833000-7f6ae7834000 rw-p 00000000 00:00 0
7ffd8a23b000-7ffd8a25c000 rw-p 00000000 00:00 0 [stack]
7ffd8a331000-7ffd8a333000 r--p 00000000 00:00 0 [vvar]
7ffd8a333000-7ffd8a335000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
我按照 2501 的建议重写了将列表传回调用函数的函数,但它并没有改变程序在同一位置中止的情况
此外,gdb 在评估该行时给出了这个:
realloc: Assertion `ptr == alloc_last_block' failed!
编辑 2:经过一系列调试后,是 swap() 破坏了堆,但我不知道为什么。我按照建议重写了 swap(),但是紧随其后的 realloc() 失败,而紧接其前的 realloc() 却没有
变量在 C 中按值传递。
传递给函数del
的指针list
在函数中被realloc改变了,但是函数外的指针没有改变。导致的未定义行为。
指针animal_list
,在此处传递:
del(animal_list, num_animals);
该指针的副本 list
,在此处更改:
list = realloc(list, sizeof(animal) * (size - 1));
原指针animal_list
不变
解决这个return新指针列表的值。
想通了。 swap(to_delete, &list[size])
只需要 swap(to_delete, &list[size - 1])
为愚蠢的错误欢呼
我不确定我是否在这里遗漏了什么,但是当我尝试收缩动态结构数组时,realloc() 因大小无效而失败。我将代码中的非必要功能修剪为 post:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char const file_name[] = "animals.dat";
typedef enum {
false, true } bool;
typedef struct {
char month;
char day;
short year;
} date;
typedef struct {
bool parvo_vacc;
bool fip_vacc;
bool rabies_vacc;
bool has_mc;
bool worm_vacc;
} md_history;
typedef struct {
int id;
char age;
char name[25];
char description[50];
md_history medical;
date intake_date;
date adopt_date;
} animal;
void lookup(animal* list, int size);
int compare(const void* this, const void* that);
void sort(animal* list, int size);
//this brings the new name back with it, since it isnt saved correctly
//in the new animal
animal* add(char* name);
void del(animal* list, int size);
void print_results(animal** results, int size);
void print_animal(animal* print);
void swap(animal* this, animal* that);
int main(int argc, char **argv)
{
FILE* readfile = fopen(file_name, "r");
if (readfile == NULL)
{
printf("Error file not found: %s\n", file_name);
}
//read data using fread(), keeping track of the number
//of bytes missed
int num_animals = 0;
fread(&num_animals, sizeof(int), 1, readfile);
animal* animal_list = (animal*) calloc(num_animals, sizeof(animal));
int errnum = num_animals - (fread(animal_list,
sizeof(animal), num_animals, readfile));
if (errnum > 0)
{
printf("Read encountered %d errors", errnum);
}
fclose(readfile);
char c;
char* name = malloc(sizeof(char) * 25);
//switch statements dont allow declarations for whatever reason
int x;
while(c != 'q')
{
printf("Options: (l)ookup (s)ort (a)dd (d)elete (p)rint (q)uit (e)dit\n");
scanf(" %c", &c);
switch (c)
{
case 'l':
lookup(animal_list, num_animals);
break;
case 's':
sort(animal_list, num_animals);
break;
case 'p':
for (x = 0; x < num_animals; x++)
{
print_animal(&animal_list[x]);
}
break;
case 'a':
//after dealing with lots of iostream errors trying to
//set the name field in add(), i decided to just return
//the new name to here and strcpy it
animal_list = realloc(animal_list, sizeof(animal) * (num_animals + 1));
swap(&animal_list[num_animals], add(name));
strcpy(animal_list[num_animals].name, name);
num_animals++;
//memory leak here, since switch statements dont allow
//declarations, i cant save the new animal pointer to a temp
//var so it can be deleted
break;
case 'd':
del(animal_list, num_animals);
num_animals--;
break;
}
}
return 0;
}
void swap(animal* this, animal* that)
{
animal temp;
temp.id = this->id;
strcpy(temp.name, this->name);
temp.age = this->age;
strcpy(temp.description, this->description);
temp.medical.fip_vacc = this->medical.fip_vacc;
temp.medical.has_mc = this->medical.has_mc;
temp.medical.parvo_vacc = this->medical.parvo_vacc;
temp.medical.rabies_vacc = this->medical.rabies_vacc;
temp.medical.worm_vacc = this->medical.worm_vacc;
temp.intake_date.day = this->intake_date.day;
temp.intake_date.month = this->intake_date.month;
temp.intake_date.year = this->intake_date.year;
temp.adopt_date.day = this->adopt_date.day;
temp.adopt_date.month = this->adopt_date.month;
temp.adopt_date.year = this->adopt_date.year;
this->id = that->id;
strcpy(this->name, that->name);
this->age = that->age;
strcpy(this->description, that->description);
this->medical.fip_vacc = that->medical.fip_vacc;
this->medical.has_mc = that->medical.has_mc;
this->medical.parvo_vacc = that->medical.parvo_vacc;
this->medical.rabies_vacc = that->medical.rabies_vacc;
this->medical.worm_vacc = that->medical.worm_vacc;
this->intake_date.day = that->intake_date.day;
this->intake_date.month = that->intake_date.month;
this->intake_date.year = that->intake_date.year;
this->adopt_date.day = that->adopt_date.day;
this->adopt_date.month = that->adopt_date.month;
this->adopt_date.year = that->adopt_date.year;
that->id = temp.id;
strcpy(that->name, temp.name);
that->age = temp.age;
strcpy(that->description, temp.description);
that->medical.fip_vacc = temp.medical.fip_vacc;
that->medical.has_mc = temp.medical.has_mc;
that->medical.parvo_vacc = temp.medical.parvo_vacc;
that->medical.rabies_vacc = temp.medical.rabies_vacc;
that->medical.worm_vacc = temp.medical.worm_vacc;
that->intake_date.day = temp.intake_date.day;
that->intake_date.month = temp.intake_date.month;
that->intake_date.year = temp.intake_date.year;
that->adopt_date.day = temp.adopt_date.day;
that->adopt_date.month = temp.adopt_date.month;
that->adopt_date.year = temp.adopt_date.year;
}
void del(animal* list, int size)
{
printf("Delete by: (n)ame (i)d\n");
char c;
while (getchar() != '\n');
scanf("%c", &c);
animal* to_delete = NULL;
if (c == 'n')
{
printf("Enter name to delete: ");
char to_search[25];
while (getchar() != '\n');
scanf(" %s", to_search);
int x;
for (x = 0; x < size; x++)
{
if (strcmp(to_search, list[x].name) == 0)
{
to_delete = &list[x];
}
}
}
if (c == 'i')
{
printf("Enter ID to delete: ");
int to_search;
while (getchar() != '\n');
scanf("%d", &to_search);
int x;
for (x = 0; x < size; x++)
{
if (to_search == list[x].id)
{
to_delete = &list[x];
}
}
}
swap(to_delete, &list[size);
list = realloc(list, sizeof(animal) * (size - 1)); //fails right here
}
我是否错误地缩小了数组?我在这里很困惑
编辑:我知道 realloc() 失败了,因为它做得非常好并中止,给出了这条消息:
*** Error in `./final': realloc(): invalid next size: 0x0000000000c11250 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x77725)[0x7f6ae72ba725]
/lib/x86_64-linux-gnu/libc.so.6(+0x82bfa)[0x7f6ae72c5bfa]
/lib/x86_64-linux-gnu/libc.so.6(+0x85179)[0x7f6ae72c8179]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x22f)[0x7f6ae72c6e6f]
./final[0x401d3e]
./final[0x400b82]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f6ae7263830]
./final[0x400849]
======= Memory map: ========
00400000-00403000 r-xp 00000000 08:01 3146140 /home/destrovel/cppwork/final
00602000-00603000 r--p 00002000 08:01 3146140 /home/destrovel/cppwork/final
00603000-00604000 rw-p 00003000 08:01 3146140 /home/destrovel/cppwork/final
00c10000-00c31000 rw-p 00000000 00:00 0 [heap]
7f6ae0000000-7f6ae0021000 rw-p 00000000 00:00 0
7f6ae0021000-7f6ae4000000 ---p 00000000 00:00 0
7f6ae702d000-7f6ae7043000 r-xp 00000000 08:01 1069105 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6ae7043000-7f6ae7242000 ---p 00016000 08:01 1069105 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6ae7242000-7f6ae7243000 rw-p 00015000 08:01 1069105 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6ae7243000-7f6ae7403000 r-xp 00000000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7403000-7f6ae7602000 ---p 001c0000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7602000-7f6ae7606000 r--p 001bf000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7606000-7f6ae7608000 rw-p 001c3000 08:01 1049974 /lib/x86_64-linux-gnu/libc-2.23.so
7f6ae7608000-7f6ae760c000 rw-p 00000000 00:00 0
7f6ae760c000-7f6ae7632000 r-xp 00000000 08:01 1049970 /lib/x86_64-linux-gnu/ld-2.23.so
7f6ae77f9000-7f6ae77fc000 rw-p 00000000 00:00 0
7f6ae782e000-7f6ae7831000 rw-p 00000000 00:00 0
7f6ae7831000-7f6ae7832000 r--p 00025000 08:01 1049970 /lib/x86_64-linux-gnu/ld-2.23.so
7f6ae7832000-7f6ae7833000 rw-p 00026000 08:01 1049970 /lib/x86_64-linux-gnu/ld-2.23.so
7f6ae7833000-7f6ae7834000 rw-p 00000000 00:00 0
7ffd8a23b000-7ffd8a25c000 rw-p 00000000 00:00 0 [stack]
7ffd8a331000-7ffd8a333000 r--p 00000000 00:00 0 [vvar]
7ffd8a333000-7ffd8a335000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
我按照 2501 的建议重写了将列表传回调用函数的函数,但它并没有改变程序在同一位置中止的情况
此外,gdb 在评估该行时给出了这个:
realloc: Assertion `ptr == alloc_last_block' failed!
编辑 2:经过一系列调试后,是 swap() 破坏了堆,但我不知道为什么。我按照建议重写了 swap(),但是紧随其后的 realloc() 失败,而紧接其前的 realloc() 却没有
变量在 C 中按值传递。
传递给函数del
的指针list
在函数中被realloc改变了,但是函数外的指针没有改变。导致的未定义行为。
指针animal_list
,在此处传递:
del(animal_list, num_animals);
该指针的副本 list
,在此处更改:
list = realloc(list, sizeof(animal) * (size - 1));
原指针animal_list
不变
解决这个return新指针列表的值。
想通了。 swap(to_delete, &list[size])
只需要 swap(to_delete, &list[size - 1])
为愚蠢的错误欢呼