【问题标题】:Why is malloc( ) initializing the value of a newly allocated block of memory?为什么 malloc() 初始化新分配的内存块的值?
【发布时间】:2013-07-14 11:46:55
【问题描述】:

我开始学习 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()。

【问题讨论】:

  • 我认为这是因为您分配的内存之前没有被其他非零变量使用。你不能确定它总是如此。
  • 似乎是未定义的行为。再重复几次,检查你是否仍然得到 0。
  • 如果你想要一个零初始化区域,只需使用calloc
  • 在多用户操作系统上,当操作系统给你一个新的内存页面时,它必须是“干净的”,这样你就看不到任何你不应该看到的东西。实现此目的的一种简单方法是为您提供一个充满零的页面。
  • 您只进行了 1 个 malloc 调用。您的操作系统(不是“malloc”)通常会分发清零的新内存,以免从之前使用该内存的其他进程泄漏信息。我建议你做一些 malloc,用一些东西填充内存,free() 它,然后再 malloc()。由于重复使用相同的内存,因此您获得旧东西的机会更大。

标签: c dynamic-allocation


【解决方案1】:

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

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

Why does malloc initialize the values to 0 in gcc?

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

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

【讨论】:

  • @ItaloGrossi 没问题。快乐编码
【解决方案2】:

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

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

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

【讨论】:

  • 您好 Huseyin 感谢您的出色回复。我已经按照你的建议做了。 1 - 使用 malloc 为 5 个 int 值分配内存。 2 - 使用 srand() 和 random() 随机初始化 5 个整数 3 - 打印值 4 - 使用 free() 5 - 为 5 个 int 值分配新内存 6 - 再次打印值 令我惊讶的是,步骤上打印的值6 是第 3 步中的旧值。所以你是对的……这次新分配的内存没有用零初始化。相反,它只是从第 2 步中获取随机值。
  • 但是您可能需要扫描整个编译器的工作区域以确保获得非零值 :) 这可能需要许多 malloc。 :) 玩得开心。
【解决方案3】:

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

您的代码中没有初始化。

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

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

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

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

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

      【讨论】:

        【解决方案6】:

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

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

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

        【讨论】:

          猜你喜欢
          • 2021-10-16
          • 2022-09-27
          • 1970-01-01
          • 1970-01-01
          • 2011-12-23
          • 1970-01-01
          • 2021-01-08
          • 2016-02-13
          • 1970-01-01
          相关资源
          最近更新 更多