如果Realloc()失败,调用者是否会丢失上次调用malloc()时的数据?

问题描述 投票:0回答:1

以下是某次考试中的一段话(1%顶尖大学)。

我失败了,因为我的答案与 "认可 "的答案不同。

我有一种预感,他(教授,著名的C语言专家)的答案不正确。

下面,是 "认可 "答案后的问题。

下面的函数中存在一个潜在的bug。是什么,如何修复?

提示:这与realloc()函数的使用有关。请找出你要更改的行号,以及用什么来代替它们。

BOOLEAN lengthen_string(char* string, const char newcontents[])
{
        int newlen = strlen(string) + strlen(newcontents) + 1;
        string = realloc(string, newlen);

        if (!string) {
                perror("malloc");
                return FALSE;
        }

        strcat(string, newcontents);
        return TRUE;
}

教授提供的 "正确 "答案是。

第4行:当分配失败时,realloc会返回一个NULL指针。这意味着在失败时,原来的数据会丢失。

要解决这个问题,可以将realloc的结果分配给一个临时变量,先测试一下。

即:第4行。

char * temp=realloc(string, newlen);
if(!temp) ... (all remains the same)

在旧的第9行之后, string = temp;

有什么想法吗?

另外,我的答案是@string是一个局部变量,函数的原型应该是 char **string,其中调用者将一个指针传递给它的字符串指针,然后被调用者将把任何realloc()返回值分配给 *string

有什么想法吗?

c memory malloc glibc realloc
1个回答
6
投票

你们都是正确的。

教授是正确的,因为 realloc() 在失败时,不会改变传入的内存,因此留下输入的 string 指针完好无损,但如果失败时的NULL返回值被立即赋值给 string 那么原来的数据就会丢失和泄露。所以在将新指针值赋给 string.

你是对的,在这一点上 string 需要通过指针来传递,以便在遇到 realloc() 返回一个不同的内存地址。

正确的解决方案应该是这样的。

BOOLEAN lengthen_string(char** string, const char newcontents[])
{
    if (!string)
    {
        errno = EINVAL;
        perror("bad input");
        return FALSE;
    }
    size_t newsize = strlen(*string) + strlen(newcontents) + 1;
    char *temp = realloc(*string, newsize);
    if (!temp)
    {
        perror("realloc failed");
        return FALSE;
    }
    strcat(temp, newcontents);
    *string = temp;
    return TRUE;
}

另外,还有一些优化的空间,例如:

BOOLEAN lengthen_string(char** string, const char newcontents[])
{
    if (!string)
    {
        errno = EINVAL;
        perror("bad input");
        return FALSE;
    }
    char *temp;
    if (!*string)
    {
        temp = strdup(newcontents);
        if (!temp)
        {
            perror("strdup failed");
            return FALSE;
        }
    }
    else
    {
        size_t offset = strlen(*string);
        size_t size = strlen(newcontents) + 1;
        temp = realloc(*string, offset + size);
        if (!temp)
        {
            perror("realloc failed");
            return FALSE;
        }
        memcpy(temp + offset, newcontents, size);
    }
    *string = temp;
    return TRUE;
}
© www.soinside.com 2019 - 2024. All rights reserved.