4

我开始学习 C 中的动态内存分配,到目前为止,我读过 malloc() 函数的所有地方都没有初始化新分配块的值。

这在 C 的较新版本中是否已更改?C99和C11?

我正在使用 Xcode 执行以下操作,并且所有值都被初始化为 0。

double *p = (double *) malloc(5 * sizeof(double));

printf("Address of p0 = %p | Valoe of p0 = %f\n", p, *p);
printf("Address of p1 = %p | Valoe of p1 = %f\n", p+1, *(p+1));
printf("Address of p2 = %p | Valoe of p2 = %f\n", p+2, *(p+2));
printf("Address of p3 = %p | Valoe of p3 = %f\n", p+3, *(p+3));
printf("Address of p4 = %p | Valoe of p4 = %f\n", p+4, *(p+4));

我认为这仅适用于函数 calloc()。

4

6 回答 6

10

似乎是实现定义的行为。在 Visual Studio 2012、C 编译器上,我看不到这样的初始化。

更重要的是,阅读此问题中所选答案的“catch”:

为什么 malloc 将 gcc 中的值初始化为 0?

说,由于安全原因,操作系统可能会“给”你归零的值。看起来,这是一个实现定义的行为。

一条建议:它不是标准行为并且破坏了代码的可移植性。确保初始化这些值,而不是依赖于 OS 提供的数据。

于 2013-07-14T11:50:26.423 回答
4

你很幸运(如果你相信这一点,你会很不幸)。Malloc 内部没有这样的东西(但它要求操作系统进行分配,我不知道操作系统的行为)。然后,当您反复 malloc 某些区域时,性能可能会有所下降。那些零来自未受破坏的森林。

首先 malloc,然后初始化为随机数/字符,然后重复多次,然后您将在 malloc 之后开始获取非零元素。

不要忘记在随机大小的 malloc 之间释放()。

于 2013-07-14T11:49:12.050 回答
3

您假设“我得到 0”总是意味着“值 0 是故意放在这里的”,但事实并非如此。

您的代码中没有初始化。

于 2013-07-14T11:58:34.110 回答
2

首先,malloc没有按照标准初始化返回的内存块(这没有改变)的事实并不意味着它一定不能这样做,而是不需要这样做

无论如何malloc初始化内存块是非常好的。甚至可以想象(但不明智)调试版本将所有分配的块初始化为零。然而,更好的解决方案是用可识别的模式填充它们。

最重要的是,从操作系统获得的新页面总是归零。这样做是出于安全原因,没有例外(一些嵌入式系统可能是罕见的例外,但没有“主流”系统会给你一个未初始化的页面,永远)。因此,在某些情况下,内存可能是零初始化的,但您无法知道它是malloc在做这件事还是其他人做的。

于 2013-07-14T11:57:46.950 回答
0

在多用户操作系统中,当操作系统将内存分配给进程时,操作系统通常会清除内存,以便它不会泄露之前来自其他进程的数据。(当然,系统不必将此内存归零;为了保护隐私,它只需将内存设置为不包含私有数据的任何值。通常使用零。)

这意味着当malloc返回从操作系统新获得的内存时,这当然发生在malloc以前的内存池不足以满足您的请求时,该内存将包含零。但是,当malloc返回您的进程先前使用的内存时,它可能包含其他数据。(其中一些数据可能来自您通常不可见的程序部分,例如 C 运行时初始化代码或动态加载器和链接器。)

由于此行为是您的操作系统而非 C 规范的结果,因此当软件仅基于 C 规范时,您可能不依赖它。当您无法保证会发生这种行为时,您必须编写软件,好像每个都malloc可以返回未初始化的数据,即使经验或检查经常表明并非如此。

于 2013-07-14T13:27:23.960 回答
0

分配块的内容没有定义,因此它是特定于实现的。

某些实现(例如您正在使用的这个)将其设置为零,其他实现0xdeadbeef或其他一些幻数(msvc++ 编译的 malloc 填充它0xCC但不是全部)。

它是特定于实现的,因此未定义,不要依赖它。

并且永远不要仅仅因为它很危险就在内存中重新分配内存。

于 2013-07-14T12:43:53.857 回答