致电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);
答案 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之后将无法再使用。这将产生非常不可预测的行为,并可能导致分段错误。