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])

为愚蠢的错误欢呼