在最近切换到c之后,我在周日的时候被告知,引用一个尚未初始化的值不是很好的做法,并且会导致意外的行为。具体来说,(因为我以前的语言将整数初始化为0),我被告知未初始化时整数可能不等于零所以我决定测试一下。
我编写了以下代码来测试这个声明:

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

int main(){
    size_t counter = 0;
    size_t testnum = 2000; //The number of ints to allocate and test.
    for(int i = 0; i < testnum; i++){
        int* temp = malloc(sizeof(int));
        assert(temp != NULL); //Just in case there's no space.
        if(*temp == 0) counter++;
    }
    printf(" %d",counter);
    return 0;
}

我是这样编译的(如果重要的话):
gcc -std=c99 -pedantic name-of-file.c
根据我的导师所说的,我希望temp指向一个随机整数,并且计数器不会经常递增然而,我的结果推翻了这个假设:
testnum:  ||  code returns:
2             2
20            20
200           200
2000          2000
20000         20000
200000        200000
2000000       2000000
...           ...

结果是10(*2)的两个幂,但你得到了重点。
然后我测试了上述代码的类似版本,但我初始化了一个整数数组,将每个偶数索引设置为其先前值的加1(未初始化),释放了数组,然后执行了上面的代码,测试了与数组大小相同数量的整数(即testnum)。这些结果更有趣:
testnum:  ||  code returns:
2             2
20            20
200           175
2000          1750
20000         17500
200000        200000
2000000       2000000
...           ...

基于此,可以合理地得出结论,c重用了已释放的内存(显然),并设置了一些新的整数指针来指向包含先前递增整数的地址我的问题是为什么第一次测试中的所有整数指针始终指向0它们不应该指向堆上我的计算机提供的程序的任何空格吗,这些空格可能(并且应该在某个时刻)包含非零值?
换言之,为什么我的c程序访问的所有新堆空间似乎都被清除到了0?

最佳答案

正如您已经知道的,您正在调用未定义的行为,因此所有的赌注都是关闭的为了解释您观察到的特定结果(“为什么未初始化的内存没有全部写入零?”),您首先必须了解malloc是如何工作的。
首先,malloc不只是在每次调用时直接向系统请求页面。它有一个内部“缓存”,从中可以给你内存假设你打了两次电话第一次调用malloc(16)时,它将扫描缓存,查看是否为空,并从操作系统请求一个新页面(大多数系统上为4KB)。然后,它将此页拆分为两个块,给出较小的块,并将另一个块保存在其缓存中。第二次调用malloc(16)时,它将看到缓存中有足够大的块,并通过再次拆分该块来分配内存。
malloc(16)ing内存只是将其返回到缓存在那里,它可能(或者不可能)与其他块合并以形成更大的块,然后用于其他分配根据分配器的详细信息,如果可能的话,它还可以选择将空闲页返回给操作系统。
现在问题的第二部分——从操作系统获得的任何新页面都会被frees填满。为什么想象一下,它只是把一个未使用的页面交给了您,这个页面以前被其他进程使用过,但现在已经终止。现在您遇到了一个安全问题,因为通过扫描“未初始化的内存”,您的进程可能会找到敏感数据,如前一个进程使用的密码和私钥注意,C语言不能保证会发生这种情况(操作系统可以保证,但C规范并不关心)。有可能操作系统在页面中填充了随机数据,或者根本没有清除(特别是在嵌入式设备上)。
现在你应该能够解释你观察到的行为第一次,您从操作系统中获取新的页面,因此它们是空的(同样,这是操作系统的实现细节,而不是C语言)。但是,如果您再次0malloc,然后free,则有可能获得与缓存中相同的内存这个缓存不会被擦除,因为唯一可以写入它的进程是您自己的。因此,您只需获取以前的任何数据。
注意:这解释了特定malloc实现的行为它并不适用于所有malloc实现。

关于c - 在c中初始化整数指针,不会导致预期的未指定行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45447783/

10-11 23:17
查看更多