无法复制使用字符串时 malloc 未初始化内存的示例

Can't replicate example of malloc not initializing memory when using strings

为了更好地理解 malloccalloc 之间的差异,我试图找到一个示例,其中 malloc 从之前的分配中保留了内存 uninitialized/reuses。

我遇到了 SO 问题 Why does malloc initialize the values to 0 in gcc?

我试图复制这个例子,但分配了一个字符数组并设置了一个值。但是,似乎 malloc 在这种情况下有效,但为什么呢?

代码:

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

int main(void) {
    // this shows, that malloc does not initialize memory
    {
        double *a = malloc(sizeof(double)*100);
        *a = 100;
        printf("%f\n", *a);
        free(a);
    }
    {
        double *a = malloc(sizeof(double)*100);
        printf("%f\n", *a);
        free(a);
    }

    // tried the same with chars, but my example doesn't work
    {
        char *ptr = malloc(sizeof(char) * 10);
        ptr[0] = 'a';
        printf("%s\n", ptr);
        free(ptr);
    }

    {
        char *ptr = malloc(sizeof(char) * 10);
        printf("%s\n", ptr);
        free(ptr);
    }

    return 0;
}

输出:

$ clang -ggdb memset_test.c
$  ./a.out
100.000000
100.000000
a
<empty string>

我看不出区别,为什么第一个使用双打的 exable 有效,而我的却不行?

那是 OS 系统相关的(正如@Basile Starynkevit 在评论中更清楚地指出的 特定实施 )。正如您所知,malloc 不会将其归零,但 OS 可以做到这一点(这显然取决于 OS)。

在我的系统上,我得到的输出为 -

 100.000000
 0.000000
 a
 02T               // excat output that I get on my system

但是很明显我们访问的是未初始化的内存。所以,UB。所以我们不能期待任何想要的输出。

在每种情况下,在第二次 malloc() 调用后取消引用指针的行为是未定义的。

未定义行为的核心定义(是的,标准确实说明了 "undefined" 的含义,尽管这看起来很讽刺)是允许发生任何事情。这可能包括看起来像您预期的那样工作,在一种情况下如您预期的那样工作而在另一种情况下不工作,等等。

您可能会看到不一致行为(两个相似的示例,但只有一个按预期工作)的原因通常归结为编译器如何在内存中组织数据、标准库实现如何在内存中组织数据、您的操作系统管理内存(因此 malloc() 到 return 最后一个 free()d 指针的可能性有多大),主机上有多少物理内存可用,等等。这些东西都相互作用,并且没有任何保证。

尝试为 double 分配与第一个 malloc 中相同数量的内存:

char *ptr = malloc(sizeof(char) * 800);

glibc's malloc implementation 中,小内存块与大内存块的处理方式不同,您应该打印出返回指针的值,以查看它是同一个内存块。

这是free,它可能会覆盖以前的内部记账数据(空闲内存块列表)。