41

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

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

int main () {

    int* ptr = NULL;
    ptr = realloc(ptr, 10*sizeof(int));
    return 0;
}

realloc使用初始NULL值分配内存有什么危险ptr吗?如果不是:

int* ptr = NULL;

我有这个:

int* ptr; // no value given to ptr

realloc调用using会有问题ptr吗?

4

3 回答 3

54

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

没有任何

7.22.3.5

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

对于第二部分:

int* ptr; // no value given to ptr

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

如果您使用的是未初始化的指针,那么这确实是一个非常严重的问题,因为您无法预测它们的值是什么。该函数realloc仅适用于NULL或从malloc/获得的值realloc

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

于 2012-08-26T22:14:23.557 回答
10

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

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

有些人认为最好malloc()在初始分配和realloc()之后使用。这个建议是有道理的,尤其是因为你可能不会使用ptr = realloc(ptr, 0);来释放内存,即使你可以这样做(所以你并不真正需要malloc()或者free()因为realloc()可以执行所有三个操作)。但是 C90 标准要求realloc(0, new_size)与 等效地工作malloc(new_size),而且我知道没有表现不同的 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;
}

有什么危险?危险在于,如果第二次或随后的内存分配失败并且ptr是指向已分配内存的唯一指针,您只需用 null 覆盖其先前的值。这意味着您不能再释放分配的内存ptr——您已经泄漏了内存。(对于第一次分配,初始值为 0,被覆盖的值为 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;
}

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

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

于 2012-08-26T22:56:22.607 回答
4

使用最初为 NULL 值的 ptr 使用 realloc 分配内存有什么危险吗?

不,那将完全像一个malloc.

如果不是:

int* ptr = NULL;

我有这个:

int* ptr; // no value given to ptr

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

是的,会有问题。如果realloc没有得到 a NULL,它将尝试从该位置开始扩展内存,或者可能会尝试freemalloc另一部分内存。由于未初始化的变量可以具有任何值,因此机会非常高,它们不是realloc喜欢的值。如果幸运的话,您的程序会立即崩溃。

于 2012-08-26T22:15:31.670 回答