是malloc()初始化分配数组为零?
这里是我使用的代码:是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;
}
程序不打印OK
。 malloc
不应该将分配的内存初始化为零。这是为什么发生?
的malloc手册页说:
的malloc()函数函数分配size个字节,并返回一个指针 分配的内存。 内存未初始化。如果大小为0,则 ,则malloc()返回NULL,或者稍后可以将 成功传递给free()的唯一指针值。
所以,malloc()
返回未初始化内存,其内容是不确定的。
if (arr[i] != 0)
在你的程序中,你曾经试图访问一个内存块,这是调用未定义行为的内容。
malloc不应该将分配的内存初始化为零。
由malloc
分配的内存未初始化。这些地点的价值是不确定的。在这种情况下,如果该位置的值是该类型的陷阱表示,则访问该内存可能会导致未定义的行为。
n1570-§6.2.6.1(P5):
某些对象表示不一定表示该对象类型的值。如果一个对象的存储值有这样的表示,并且被一个没有字符类型的左值表达式读取,那么这个行为是不确定的。 [...]
和脚注表示:
因此,自动变量可以被初始化为陷阱表示,而不会导致未定义的行为,但该变量的值不能被使用,直到一个适当的值存储在其中。
如果行为不确定,则可以预料没有什么好处。您可能会得到预期的结果,也可能得不到预期的结果。
void *malloc(size_t size)
只是应该放在指定的空间量。就这样。无法保证在该空间中会出现什么。
从man页面引用:
的
malloc()
函数分配size个字节,并返回一个指针 分配的内存。内存未初始化。如果size
为0, 则malloc()
返回NULL,或者返回一个唯一的指针值,后面的 可以成功传递给free()
。
除了calloc()
,您可以使用memset()
函数来清零内存块。
malloc
不应该将分配的内存初始化为零。这是为什么发生?
这是40多年前的设计。
但是,同时创建了calloc()
函数,将分配的内存初始化为零,它是为阵列分配内存的推荐方式。
行:
arr = (int *)malloc(sz * sizeof(int));
应改为:
arr = calloc(sz, sizeof(int));
如果是从一本旧书它教学习C你总是投以malloc()
或calloc()
(一void *
)返回的值到您分配值的变量类型(您的案例中为int *
)。如果将由malloc()
或calloc()
返回的值直接分配给变量,则这已过时,现代版本的C不需要再进行强制转换。
GCC文档:_除了赋值操作符_以外的其他上下文中需要强制转换。 –
@RyanB。 - GCC在这里不符合C标准。 'void *'可以隐式转换为所有对象类型。不需要强制转换。 – StoryTeller
从C标准7.22.3.4:
梗概
#include <stdlib.h>
void *malloc(size_t size);
说明
malloc函数为一个对象,其大小分配空间由大小指定 并且其价值不确定。
值为不确定。所以,每个编译器都可以自由地表达它的想法。例如,在Microsoft Visual C++中,在Debug
模式下,malloc()
分配的内存区域全部设置为0xCDCDCDCD
,并且在Release
模式下它是随机的。在现代版本的GCC中,如果您不启用代码优化,则将其设置为0x000000,否则将其设置为随机值。我不知道其他编译器,但你明白了。
您第一次打电话给malloc(3)
时,它会要求操作系统为堆空间获取内存。
出于安全原因,unix/linux内核(以及许多其他操作系统)通常会将要提供给进程的页面内容归零,因此没有进程可以访问该内存的先前内容并使用它进行恶意操作(如搜索旧密码或类似的东西)。
如果您执行多次内存分配和释放,malloc模块重新使用之前的内存时,您会看到来自malloc(3)
的垃圾。
内存的内容是* indeterminate *。它可能看起来是随机的。或者它可能全部为零。你根本不知道事先。 –
*“程序不打印OK,malloc不应该将分配的内存初始化为零。”* - 它也不能保证*不是全部为零。无论哪种方式,通过读取不确定的值,您的程序具有未定义的行为。你无法期待任何事情。 – StoryTeller
此外,调试构建可能实际上会导致您分配的内存甚至局部变量被初始化。使内存和指针问题更易于检测。 –