在C中调用free()

当我打电话给free(a)时到底发生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); 

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

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

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

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

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

如果释放这样的内存块,则在堆的末尾可以减小堆大小,从而使内存无效并使进一步的访问崩溃。 虽然分配器不会增加或减少堆大小只有几个字节,所以在这一点上它取决于分配的大小和释放的块数。 它可能是可访问的,也可能不是。

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

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

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

是的,这正是它的意思。 一旦调用free() ,就会返回有问题的内存以供操作系统使用。 它可能看起来仍然有效,但是你会导致未定义的行为。

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

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

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

释放内存后,您无法对其可能包含的内容做出任何假设。 所以你不应该再访问它了。

当您调用free(a) ,表示内存已被标记为可重用。 因此,将数组写入一个仍然有效,但它是未定义的行为。 如果没有您的通知,它可能会被覆盖。

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

做这个:

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

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

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

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

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

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