在C中调用free()

时间:2013-02-20 17:48:34

标签: c free

致电free(a)时究竟发生了什么?我知道它释放了所使用的内存,但这是否也意味着无法再访问存储在数组a中的数据(因此无法调用copyArray)?

int *a = (int *) malloc(sizeof(int) * numberOfInts);
for (i = 0; i < numberOfInts; i++) {
        a[i] = random();
        printf("%d\n", a[i]);
    }
    free(a);
    copyArray(*a++, numberOfInts);

7 个答案:

答案 0 :(得分:3)

  

当我打电话给免费(a)时究竟发生了什么?

这是特定于实现的。例如,使用Linux和glibc,可能会发生以下几种情况之一:

如果内存是在128k或更多的块中分配的,glibc将分配一个新的内存区域(具体地说,mmap的写入时复制/dev/zero)。当它被释放时,内存区域被简单地解除分配(munmap'd)并消失。进一步的访问将崩溃。

如果分配的内存较小,它将在堆上。堆是从固定地址开始的单个内存区域,其大小可以使进程缩小或增加(使用sbrk)。

内存分配器会保留分配此区域的哪些部分的跟踪。第一次分配内容时,堆的大小会增加,内存将附加到此新空间的末尾。

如果释放这样的内存块,则在堆的末尾可以减小堆大小,从而使内存无效并使进一步的访问崩溃。尽管如此,分配器不会增加或减少堆大小,因此在此时它取决于分配的大小和释放的块数。它可能是可访问的,也可能不是。

如果你分配了10块内存并释放了前9块,你最终会在堆中找到一个未使用的区域。由于您只能通过设置结束地址来修改堆大小,因此您无法对其进行任何操作。内存仍然有效,访问它仍然有效。您甚至可能会在其中找到原始数据,并且可以继续,就好像什么也没发生一样。

但是,在分配新内存时,malloc会尝试将其放入此未使用的区域,从而让其他数据覆盖原来的内容。在free'd数组中设置int然后可以覆盖程序中完全不相关的部分中的指针,然后进行欢闹和调试。

tl; dr:不要访问free'd内存!

答案 1 :(得分:1)

是的,这正是它的含义。只要您调用free(),就会返回相关内存以供操作系统使用。它可能看起来仍然有效,但是你会导致未定义的行为。

答案 2 :(得分:1)

您不应访问已释放的内存位置。是的,无法再访问存储在这些位置的数据。但是访问释放的位置会导致不确定的行为。

答案 3 :(得分:1)

  

但这也意味着无法再访问存储在数组a中的数据

是的 - 更准确地说,访问它(即解除引用无效指针)会导致未定义的行为,因此您的程序可以执行任何(包括崩溃,它可能会)。

答案 4 :(得分:0)

当释放内存时,你不能对它可能包含的内容做任何假设。所以你不应该再访问它了。

答案 5 :(得分:0)

当您致电free(a)时,表示内存已被标记为可重复使用。因此,将数组写入a仍然工作,但它是未定义的行为。如果没有您收到通知,它可能会被覆盖。

其次,不要在C中转换malloc()的返回值。

这样做:

int *a = malloc(sizeof(*a) * numberOfInts);

此外,在C99中,您可以使用VDA来执行此操作:

printf("Enter array length: ");
scanf("%d",&numberOfInts);
int a[numberOfInts];

您不必手动取消分配这些数组。但请注意,VLA的长度有限制

答案 6 :(得分:0)

当你使用'malloc'时,你正在动态分配一个指向的内存块。通常,虽然特定于实现,但动态分配的内存存储在堆上。如果没有自由调用,当超出范围时,你将会泄漏内存。

您创建的内存块(由a指向)在调用free之后将无法再使用。这将产生非常不可预测的行为,并可能导致分段错误。