调用realloc后,我需要初始化(设置为0)内存吗?

7

我需要实现一个简单的动态指向 typedef 类型的指针数组。
每当用户请求时,使用 realloc,数组大小会增加 sizeof(pointer)。
所以我目前的代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void* node;

void printmem(node* a, int c) {
    int i;
    for (i = 0; i < c; ++i)
    {
        printf("%d\t\t%p\n", i, a[i]);
    }
}

int main(void) {
    node* nodes = NULL;
    int i = 0, count = 20;

    for (i = 0; i < count; ++i)
    {
        nodes = realloc(nodes, sizeof(node));
    }
    printf("Done reallocating\n");
    printmem(nodes, i);
    // free(a);
    return 0;   
}

这将产生以下输出:
Done reallocating
0       (nil)
1       (nil)
2       (nil)
3       0x20fe1
4       (nil)
5       (nil)
6       (nil)
7       (nil)
8       (nil)
9       (nil)
10      (nil)
11      (nil)
12      (nil)
13      (nil)
14      (nil)
15      (nil)
16      (nil)
17      (nil)
18      (nil)
19      (nil)

我关注第三个元素及其内容。因此,我想知道在进行新的realloc之后是否应该将内存设置为0。
编辑: 因此,根据H2CO3提供的C标准,对realloc的新调用如下: nodes = realloc(nodes, (i+1)*sizeof(node)); 然后,我进行了初始化: nodes[i] = NULL 这也很好地工作了。
编辑2:现在我有这个:
int main(void) {
    node* nodes = NULL;
    int i = 0, count = 20;

    for (i = 0; i < count; ++i)
    {
        nodes = realloc(nodes, (i+1)*sizeof(node));
        nodes[i] = NULL;
        if (i == 1) {
            nodes[i] = &count;
        }
    }
    printf("Done reallocating\n");
    printmem(nodes, i);
    printf("\t*nodes[1] == %d\n", *(int*)nodes[1]);
    printf("\tAddress of count is %p\n", &count);
    // free(a);
    return 0;   
}

1
realloc()会复制原始缓冲区中的所有内容。如果新块比原始块大,则末尾的元素(即原始数组中不存在的元素)将未初始化。 - user529758
1
你的realloc调用并没有像你想象的那样工作。你并没有扩展分配,而是重复分配相同大小的块。这意味着你的printmem函数已经超出了你实际分配的内存范围。 - Nigel Harper
@H2CO3:这就是让我困惑的地方,“将复制缓冲区中最初的内容”,不管怎样,谢谢你的评论 :) - Chris
@Chris 不是“by”,而是“to”。请阅读标准中相关的段落:7.20.3.4。 - user529758
@H2CO3:啊,现在我明白了!非常感谢你,H2CO3! - Chris
显示剩余3条评论
3个回答

13

嗯,这要看情况。您是否需要将内存初始化为0?如果不需要,则不需要进行任何操作。就像使用malloc一样,realloc也不执行任何初始化操作。原始块中不存在的任何内存都会保持未初始化状态。


那么我应该为每次添加的特定新元素调用memset吗? - Chris
这完全取决于你是否需要初始化这个内存。如果需要,那么是的。然而,重要的是要意识到C语言并不保证空指针由所有零位表示,只保证它将与0相等。这是一个微妙但重要的区别。 - Ed S.

2

根据realloc()的定义:

realloc(void *p, size_t size) 改变指向 p 的对象的大小为 size。内容将保持不变,最小值为旧大小和新大小。如果新的大小更大,则新空间未初始化。(来自Kernighan和Ritchie)

您可能需要初始化新空间。当决定void*指向的地址将保存何种数据时,可以执行此操作。


2
请注意,在C语言中,空指针不一定等于字面值0。它仅仅保证不等于任何有效的指针。此外,空指针在技术上允许对不同的指针类型(如函数指针和字符指针)具有不同的值。
因此,简单地将内存初始化为零可能会引发未定义的行为。
引用块中说:“因此,初始化为NULL是正确的!这就是我所做的!”——Chris
不,你需要像这样转换空指针:(void*)NULL,并将其写入内存位置。但你实际上从未写入你通过realloc分配的内存(通过传递NULL)。你基本上只是读取未初始化的内存(这是未定义的行为),然后在printf中使用。

所以将其初始化为NULL是正确的!这就是我所做的! - Chris
请问一下(void*)NULL和NULL有什么区别?我都用过,并且在valgrind中运行程序时没有出现错误。另外,为什么我没有写入我分配的内存?我已经更新了主函数,如果你运行它,你会看到nodes[1]打印了c变量的地址,通过打印*(nodes[i]),我得到了c的值。 - Chris
@Chris:如果在某些架构上,nullptr!=zero,则编译器必须知道将适当的值放入内存。它必须知道所引用的内存位应被视为指针。如果不同的指针类型具有不同的nullptr值,则编译器还必须知道需要写入内存的类型的空指针。 - EOF
感谢您的解释EOF! - Chris
请注意,在C语言中,空指针不一定等于字面值0。我想你的意思是NULL值不能保证具有零表示法。在指针上使用0字面量而不是NULL宏是可以的。 - Volodymyr Boiko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接