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

p b*_*inb 3 c memory malloc glibc realloc

以下是考试的引述(1% 的顶尖大学)。

我失败了,因为我的答案与“批准”的答案不同。

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

以下是问题后跟“批准”的答案。

以下功能存在潜在错误。它是什么,我将如何修复它?

提示:这与 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;
}
Run Code Online (Sandbox Code Playgroud)

教授提供的“正确”答案是:

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

要解决此问题,请将 realloc 的结果分配给临时变量并首先对其进行测试。

即:第4行:

char * temp=realloc(string, newlen);
if(!temp) ... (all remains the same)
Run Code Online (Sandbox Code Playgroud)

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

有什么想法吗?

顺便说一句,我的回答是 @string 是一个局部变量,函数的原型应该是 char **string,调用者传递一个指向其字符串指针的指针,然后被调用者会将任何 realloc() 返回值分配给*string

有什么想法吗?

Rem*_*eau 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;
}
Run Code Online (Sandbox Code Playgroud)

或者,还有一些优化空间,例如:

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;
}
Run Code Online (Sandbox Code Playgroud)