【问题标题】:realloc fails on shrinkrealloc 收缩失败
【发布时间】:2016-08-22 06:11:54
【问题描述】:

我不确定我是否在这里遗漏了一些东西,但是当我尝试收缩结构的动态数组时,realloc() 因大小无效而失败。我从代码中删除了非必要的功能以发布:

#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()却没有

【问题讨论】:

  • 你有没有检查过当它失败时你传递给realloc的大小是多少?
  • 您是如何确定realloc() 失败的?返回 NULL 确实 not 肯定意味着它失败了。 realloc() 可以在 0 分配以及内存不足时返回 NULL,
  • 你不应该这样调用 realloc。当 realloc 失败时,您正在覆盖列表,并且您丢失了原始指针。
  • swap(animal* this, animal* that) 很长。可以简单地使用void swap(animal* this, animal* that) { animal tmp = *this; *this = *that; *that = tmp; }。
  • scanf(" %s", to_search); 和gets(to_search) 一样糟糕。使用scanf("%24s", to_search); 有25 个字母的名字吗? IOW,发表您的意见。

标签: c dynamic realloc


【解决方案1】:

想通了。 swap(to_delete, &amp;list[size])

只需swap(to_delete, &amp;list[size - 1])

为愚蠢的错误欢呼

【讨论】:

    【解决方案2】:

    变量在 C 中按值传递。

    传递给函数del的指针list在函数中被realloc改变了,但函数外的指针没有改变。导致的未定义行为。

    指针animal_list,在这里传递:

    del(animal_list, num_animals);    
    

    该指针list 的副本在此处更改:

    list = realloc(list, sizeof(animal) * (size - 1));
    

    原来的指针animal_list保持不变。

    为了解决这个问题,返回新指针列表的值。

    【讨论】:

    • 值得一提的是,在验证成功之前,您没有使用tmp 变量来分配realloc 的返回值,从而为内存泄漏做好了准备。如果realloc 失败,它会返回NULL,并且您将失去free 最初由list 指向的内存块的能力。
    猜你喜欢
    • 1970-01-01
    • 2011-04-16
    • 2017-04-12
    • 2013-09-19
    • 2020-12-18
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    相关资源
    最近更新 更多