2017-07-26 2617 views
4

这里是我使用的代码:是malloc()初始化分配数组为零?

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

int main() { 
    int *arr; 
    int sz = 100000; 
    arr = (int *)malloc(sz * sizeof(int)); 

    int i; 
    for (i = 0; i < sz; ++i) { 
     if (arr[i] != 0) { 
      printf("OK\n"); 
      break; 
     } 
    } 

    free(arr); 
    return 0; 
} 

程序不打印OKmalloc不应该将分配的内存初始化为零。这是为什么发生?

+7

内存的内容是* indeterminate *。它可能看起来是随机的。或者它可能全部为零。你根本不知道事先。 –

+2

*“程序不打印OK,malloc不应该将分配的内存初始化为零。”* - 它也不能保证*不是全部为零。无论哪种方式,通过读取不确定的值,您的程序具有未定义的行为。你无法期待任何事情。 – StoryTeller

+0

此外,调试构建可能实际上会导致您分配的内存甚至局部变量被初始化。使内存和指针问题更易于检测。 –

回答

8

malloc手册页说:

的malloc()函数函数分配size个字节,并返回一个指针 分配的内存。 内存未初始化。如果大小为0,则 ,则malloc()返回NULL,或者稍后可以将 成功传递给free()的唯一指针值。

所以,malloc()返回未初始化内存,其内容是不确定的。

if (arr[i] != 0) 

在你的程序中,你曾经试图访问一个内存块,这是调用未定义行为的内容。

5

malloc不应该将分配的内存初始化为零。

malloc分配的内存未初始化。这些地点的价值是不确定的。在这种情况下,如果该位置的值是该类型的陷阱表示,则访问该内存可能会导致未定义的行为。

n1570-§6.2.6.1(P5):

某些对象表示不一定表示该对象类型的值。如果一个对象的存储值有这样的表示,并且被一个没有字符类型的左值表达式读取,那么这个行为是不确定的。 [...]

和脚注表示:

因此,自动变量可以被初始化为陷阱表示,而不会导致未定义的行为,但该变量的值不能被使用,直到一个适当的值存储在其中。

如果行为不确定,则可以预料没有什么好处。您可能会得到预期的结果,也可能得不到预期的结果。

2

void *malloc(size_t size)只是应该放在指定的空间量。就这样。无法保证在该空间中会出现什么。

从man页面引用:

malloc()函数分配size个字节,并返回一个指针 分配的内存。内存未初始化。如果size为0, 则malloc()返回NULL,或者返回一个唯一的指针值,后面的 可以成功传递给free()

除了calloc(),您可以使用memset()函数来清零内存块。

2

malloc不应该将分配的内存初始化为零。这是为什么发生?

这是40多年前的设计。

但是,同时创建了calloc()函数,将分配的内存初始化为零,它是为阵列分配内存的推荐方式。

行:

arr = (int *)malloc(sz * sizeof(int)); 

应改为:

arr = calloc(sz, sizeof(int)); 

如果是从一本旧书它教学习C你总是投以malloc()calloc()(一void *)返回的值到您分配值的变量类型(您的案例中为int *)。如果将由malloc()calloc()返回的值直接分配给变量,则这已过时,现代版本的C不需要再进行强制转换。

+1

GCC文档:_除了赋值操作符_以外的其他上下文中需要强制转换。 –

+0

@RyanB。 - GCC在这里不符合C标准。 'void *'可以隐式转换为所有对象类型。不需要强制转换。 – StoryTeller

2

从C标准7.22.3.4:

梗概

#include <stdlib.h> 
void *malloc(size_t size); 

说明

malloc函数为一个对象,其大小分配空间由大小指定 并且其价值不确定。

值为不确定。所以,每个编译器都可以自由地表达它的想法。例如,在Microsoft Visual C++中,在Debug模式下,malloc()分配的内存区域全部设置为0xCDCDCDCD,并且在Release模式下它是随机的。在现代版本的GCC中,如果您不启用代码优化,则将其设置为0x000000,否则将其设置为随机值。我不知道其他编译器,但你明白了。

0

您第一次打电话给malloc(3)时,它会要求操作系统为堆空间获取内存。

出于安全原因,unix/linux内核(以及许多其他操作系统)通常会将要提供给进程的页面内容归零,因此没有进程可以访问该内存的先前内容并使用它进行恶意操作(如搜索旧密码或类似的东西)。

如果您执行多次内存分配和释放,malloc模块重新使用之前的内存时,您会看到来自malloc(3)的垃圾。