由malloc()分配的数据不是零

我用'malloc()'为C语言中的结构分配内存。 部分结构如下:

struct f2fs_sb_info { struct f2fs_fsck *fsck; struct f2fs_super_block *raw_super; struct f2fs_nm_info *nm_info; struct f2fs_sm_info *sm_info; struct f2fs_checkpoint *ckpt; }; 

我发现raw_super的值总是为零,而ckpt的值总是为0x40000050

我知道malloc()不会初始化分配的内存。 所以分配的内存应该有随机值。 但是ckpt的值总是为0x40000050 ,每次运行程序都不会改变。 为什么?

分配的内存可以在分配之后存储任何值 ,但不一定是随机的 – 分配不是随机生成器。

把这看作是一个有趣的特点。

一个未初始化的变量(比如你的结构的内存分配之后的结构元素)可以取任何值。 这样的价值被认为是不确定的 。 C标准不要求以任何方式进行初始化。 请注意,读取这样的变量(除了unsigned char )的行为是未定义的,因为未初始化的值可能是陷阱表示。

为什么?

因为价值是不确定的。 并且访问一个不确定的值具有未定义的行为(如果Bathsheba指出这个类型是unsigned char ,那么它就不是UB)。

但'ckpt'的价值总是…而且不会改变

请注意,即使它迄今没有改变,也不能保证它永远不会改变。 这种价值/输出被称为“垃圾”。

你尝试过另一个编译器吗? 这可能会改变价值。 你有没有尝试修改程序的不相关的部分? 这可能会改变它。 当你运行这个程序的时候,你试过想像蝴蝶吗? 不能保证不会改变这个值,尽管你可能需要一个心灵读取适配器才能使其发挥作用。 以上都不保证改变价值。

程序化算法几乎总是确定性的,它们总是以相同的方式运行, malloc内存选择有这样的算法。

malloc通常会在运行时启动时分配一些内存池,然后使用从这个池中获取的内存来处理这些请求(如果请求的内存量非常大,它可以扩大预先分配的内存池,或者如果用户释放了很多内存的记忆)。

如果在你的代码中你分配了一些内存( malloc从池中取出),初始化它,然后在使用之后释放它,然后以相同的顺序再次重新分配它,那么你将在内部获得相同的内存块它之前初始化的相同数据非常高。 这可能是你发现的原因。

您可以尝试在另一个点使用假分配,也许作为您的程序的第一次分配,并检查值是否仍然是相同的…

无论如何,这个最终的特性必须与代码中的分配链相关,而不是与系统内存相关联,因为它的使用更为强烈,重复分配集合中的临时数据的可能性非常低。

当然这是一个UB

虽然已经有很多东西已经被指出,但是下面的代码表明,你们不可能既不能总是不变,也不能总是不变。 不能保证分配的内存是初始化的,既不是0值,也不是随机值。 malloc的结果只是指向一个称为堆的巨大内存块的地址; 在应用程序启动时,操作系统为应用程序提供了一个堆,但是不能保证操作系统将始终为您提供与应用程序堆相同的系统内存部分(可能是,但不一定是):

考虑下面的程序,mallocs相同的结构3 trimes

 struct myTestStruct { char* p1; char* p2; char* p3; char* p4; char* pToBeObserved; }; int main() { struct myTestStruct *myStructs[10]; for (int i=0; i<10; i++) myStructs[i] = (struct myTestStruct*)malloc(sizeof(myTestStruct)); for (int i=0; i<10; i++) { printf("%d'th instance; value of pToBeObserved: %p\n", i, (void*)myStructs[i]->pToBeObserved); } return 0; } 

运行此程序时的输出如下所示:

 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c 1'th instance; value of pToBeObserved: 0x0 2'th instance; value of pToBeObserved: 0x0 3'th instance; value of pToBeObserved: 0x202020202020202 4'th instance; value of pToBeObserved: 0x7fff77dd30c8 5'th instance; value of pToBeObserved: 0x100200380 6'th instance; value of pToBeObserved: 0x0 7'th instance; value of pToBeObserved: 0x0 8'th instance; value of pToBeObserved: 0x100058568 9'th instance; value of pToBeObserved: 0xc 

它表明,当你在同一个程序执行中多次保留内存时, pToBeObserved的值实际上会改变(尽管这不能保证它会改变)。 原因是,连续调用malloc指向堆的不同部分,因此pToBeObserved “查看”不同值的机会更高;

如果您一次又一次地启动程序, 可能至少第一个malloc指向堆的同一部分,并且可能是操作系统已将相同部分的系统内存分配给您的应用程序:

 Run1: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c Run3: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c Run4: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c Run5: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c Run6: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c 

但在任意运行(在我的测试中运行7),值突然改变:

 Run7: 0'th instance; value of pToBeObserved: 0x0 

此外,如果在运行期间,我改变了struct并在pToBeObserved之前添加一个成员,那么在我的测试中,下一次运行总是产生一个不同的值:

 Run1: 0'th instance; value of pToBeObserved: 0x636f6c5f6b636f6c struct myTestStruct { char added; char* p1; char* p2; char* p3; char* p4; char* pToBeObserved; }; Next run: 0'th instance; value of pToBeObserved: 0x6f5f687469775f6b 

这个例子再次表明,你只是在堆的某个地方得到一个指针,如果你改变了你的结构的内存布局(通过添加一个成员),那么成员pToBeObserved将查看(未初始化的)堆内存的不同部分。