无法复制使用字符串时 malloc 未初始化内存的示例
Can't replicate example of malloc not initializing memory when using strings
为了更好地理解 malloc
和 calloc
之间的差异,我试图找到一个示例,其中 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
,它可能会覆盖以前的内部记账数据(空闲内存块列表)。
为了更好地理解 malloc
和 calloc
之间的差异,我试图找到一个示例,其中 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
,它可能会覆盖以前的内部记账数据(空闲内存块列表)。