重新分配NULL值(或未定义)指针

30 c realloc undefined-behavior

我正在阅读realloc并对那里提到的一点感到困惑.请考虑以下代码:

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

int main () {

    int* ptr = NULL;
    ptr = realloc(ptr, 10*sizeof(int));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

realloc使用最初NULL估值的内存分配内存是否有任何危险ptr?如果不是:

int* ptr = NULL;
Run Code Online (Sandbox Code Playgroud)

我有这个:

int* ptr; // no value given to ptr
Run Code Online (Sandbox Code Playgroud)

打电话realloc使用会有问题ptr吗?

cni*_*tar 41

使用最初的NULL值ptr在realloc中分配内存是否有任何危险

没有

7.22.3.5

如果ptr是空指针,则realloc函数的行为类似于指定大小的malloc函数.

第二部分:

int* ptr; // no value given to ptr
Run Code Online (Sandbox Code Playgroud)

使用ptr调用realloc会有问题吗?

如果你正在使用未初始化的指针那么这确实是一个非常严重的问题,因为你无法预测它们的价值.该函数realloc仅适用NULLmalloc/ 或从/ 获得的值realloc.

否则,如果ptr与先前由内存管理函数[...]返回的指针不匹配,则行为未定义

  • 注意,这样做的原因是大多数malloc的实现都在指针返回之前存储块的长度(允许free知道要释放多少内存)。如果给`realloc`一个未初始化的指针,那会认为它是一个有效的指针(一个指针就是一个指针,所有的`realloc`能做的就是信任你)。然后,此实现将尝试将其前面的几个字节(size_t)解释为块的大小,这显然是不正确的。这就是为什么必须显式使指针为空,以便知道它不是有效地址的原因。 (2认同)

Jon*_*ler 8

使用显示的特定代码,最初使用空指针没有问题.

如果变量ptr未初始化 - 未设置为0或NULL - 那么任何realloc()使用它的调用都是危险的; 行为是不确定的,如果你很幸运,程序会崩溃,但是如果你运气不好,它似乎会工作一段时间,直到程序中出现问题,很难发现问题是在很久以前执行的代码中.

有人认为最好malloc()用于初始分配以及realloc()之后.这个建议有道理,尤其是因为你可能不会ptr = realloc(ptr, 0);用来释放内存,即使你可以这样做(所以你不需要malloc()free()因为realloc()可以做所有这三个操作).但是C90标准需要realloc(0, new_size)等效地工作malloc(new_size),并且我知道没有C库表现不同(但可能有一些;我只使用了一些C库,尽管大多数是最广泛使用的C库).


但是,在更一般的情况下,例如下面的代码,那么代码存在一个微妙的问题(但它与初始空指针无关):

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

int main(void)
{
    char    *ptr = NULL;
    size_t   len = 0;
    char     buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin))
    {
        size_t buflen = strlen(buffer) + 1;
        if (buflen > len)
        {
            if ((ptr = realloc(ptr, buflen)) == 0)  // Danger!
                // ... handle memory allocation failure ...
            len = buflen;
        }
        strcpy(ptr, buffer);
        // ... do something with ptr
    }
    free(ptr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有什么危险?危险在于,如果第二个或后续的内存分配失败并且ptr是指向已分配内存的唯一指针,则只需用null覆盖其先前的值.这意味着您无法再使用ptr已分配的内存- 您已泄露内存.(对于第一次分配,初始值为0,覆盖值为零,没有任何更改;没有内存泄漏.这就是循环被添加到代码中的原因.)

经验法则

  • 别写了 ptr = realloc(ptr, newsize);

将新值保存到单独的变量中,直到您对其进行测试.

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

int main(void)
{
    char    *ptr = NULL;
    size_t   len = 0;
    char     buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin))
    {
        size_t buflen = strlen(buffer) + 1;
        if (buflen > len)
        {
            char *new_ptr = realloc(ptr, buflen);
            if (new_ptr == 0)
                // ... handle memory allocation failure ...
            ptr = new_ptr;
            len = buflen;
        }
        strcpy(ptr, buffer);
        // ... do something with ptr
    }
    free(ptr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码在分配失败时不会泄漏内存.

辅助建议:不要使用名为的变量new; 这将使用C++编译器进行编译变得困难.即使您现在无意转换为C++(即使您最终可能会重写内存管理),使用C++关键字new作为C变量名称也没有任何优点......除非您明确要阻止使用C++编译器进行编译.