在c中免费呼叫时发生双重免费或损坏错误

时间:2014-07-06 07:12:11

标签: c free realloc

我是c的新手,为了学习它,我正在尝试编写一个函数来手动读取std输入中的字符。程序将从std读取行并输出它们,当它遇到空行时它将结束。

但是,如果输入流只包含三行或更少行,则它可以正常工作,但如果输入包含4行以上,则它总是停止并显示错误。调用realloc和free函数时会发生错误:'双重释放或损坏(fasttop):0x0000000001f46030 * ',为什么?

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

char *readline(int *length) {
    char ch, *s = NULL, *temp = NULL;
    int UNIT = 3, size = 0, index = 0;
    while ((ch = getchar()) != EOF) {
        if (size == 0 || index >= size) {
            size += UNIT;
            temp = realloc(s, sizeof(char) * size);
            if (s != NULL && temp != s) free(s);
            s = temp;
            temp = NULL;
        }

        s[index++] = (ch == '\n') ? '\0' : ch;
        if (ch == '\n') break;
    }
    *length = index - 1;
    return s;
}

char **readlines(int *count) {
    char **lines = NULL, **tempLines = NULL;
    int UNIT = 1, size = 0, index = 0;
    int length = 0;
    char *line = NULL;
    while ((line = readline(&length)) != NULL) {
        if (strlen(line) == 0) break;
        if (size == 0 || index >= size) {
            size += UNIT;
            tempLines = realloc(lines, size * sizeof(char *));
            if (lines != NULL && tempLines != lines) free(lines);
            lines = tempLines;
            tempLines = NULL;
        }
        lines[index++] = line;
    }
    *count = index;
    return lines;
}

int main(int argc, char *argv[]) {
    int length = 0, index = 0;
    char **lines = readlines(&length);
    printf("The lines you typed are: \n");
    for (; index < length; index++) {
        printf("%5s %s.\n", "-", lines[index]);
    }
    return 0;
}

执行结果为:

xxx@xxx:~/vmshared$ ./mylib2
abc
def
hij

The lines you typed are: 
    - abc.
    - def.
    - hij.
xxx@xxx:~/vmshared$ ./mylib2
11
22
33
44
*** Error in `./mylib2': double free or corruption (fasttop): 0x00000000017f1030 ***

5 个答案:

答案 0 :(得分:3)

你的问题在这里:

 temp = realloc(s, sizeof(char) * size);
 if (s != NULL && temp != s) free(s);

如果realloc成功,您可以在s已经释放realloc后免费{{1}}。 您可以查看此answer了解更多详情。

答案 1 :(得分:2)

您的readlinesreadline功能存在问题。你的错误是由realloc调用后释放指针引起的。

tempLines = realloc(lines, size * sizeof(char *));
if (lines != NULL && tempLines != lines) free(lines);  // wrong

temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s);  //wrong

如果将内存内容移动到另一个位置,则realloc会为您释放旧指针 在你的主要功能中,你永远不会释放你的lines指针。

答案 2 :(得分:1)

因为您正在释放数据然后使用它:

        temp = realloc(s, sizeof(char) * size);
        if (s != NULL && temp != s) free(s);

然后意味着您正在写入释放的内存 - 这很糟糕。

函数realloc可以看作:

void *realloc(void *ptr, size_t new_size)
{
    void* newptr = malloc(size);
    size_t oldsize = find_size(ptr);
    memcpy(newptr, ptr, oldsize);
    free(ptr);
    return newptr;
}

当然,REAL realloc要复杂得多(因为它检查当前块以查看它是否可以在分配新数据之前进行扩展),并且可能不会调用常规{{1} },但功能大致如此。

malloc的结果存储在与旧指针不同的变量中的原因是它返回realloc的情况 - 它无法扩展到新的大小 - 此时,你需要一个NULL和原始指针,所以你不要泄漏旧指针的内存。

答案 3 :(得分:0)

成功调用realloc后,应释放原始内存区域。

temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s) free(s); // This is wrong!

如果realloc移动您的数据,它也将释放旧区域。你自己不需要这样做。

答案 4 :(得分:0)

当您致电realloc()并且成功时,旧内存位置已被释放并返回新位置。旧位置和新位置都是相同的。但是,无论哪种方式,释放旧指针都是不正确的。立即释放新指针会很古怪。

因此,此代码不正确:

temp = realloc(s, sizeof(char) * size);
if (s != NULL && temp != s)
    free(s);
s = temp;
temp = NULL;

应该是:

temp = realloc(s, size);
if (temp == NULL)
    …report error and exit function…
s = temp;

在作业完成后没有必要设置temp = NULL;,但除了略微(无法估量地)减慢程序之外没有特别的伤害。