C 中 malloc() 函数的神秘行为
Mysterious behavior of malloc() function in C
在下面的代码中,有两个 int 数组在另一个函数中分配(我想检查我是否可以释放任何指针,或者只能释放本地分配的指针)。两个数组都以某种方式链接,我不明白为什么?
#include <stdlib.h>
#define LEN 10
int* foo(int*, int);
void main()
{
int* arr = (int*)malloc(sizeof(int) * LEN);
int* arr2 = foo(arr, LEN);
for (int i = 0; i < LEN; i++)
{
arr2[i] = i;
printf("%d\t", arr2[i]);
}
printf("\n");
for (int i = 0; i < LEN; i++)
{
printf("%d\t", arr[i]);
}
printf("\n");
for (int i = 0; i < LEN; i++)
{
arr[i] = i+1;
printf("%d\t", arr[i]);
}
printf("\n");
for (int i = 0; i < LEN; i++)
{
printf("%d\t", arr2[i]);
}
free(arr2);
}
int* foo(int* arr, int n)
{
free(arr);
return (int*)malloc(sizeof(int) * n);
}
输出为:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
调用foo
后,arr
指向的内存已经释放。然后您尝试访问 arr
指向的内存。
在释放内存后尝试使用内存会调用 undefined behavior。
首先尝试仅使用 arr
,然后调用 foo
并仅使用 arr2
。
这里arr和arr2指的是相同的内存位置。
malloc
和 free
不分配和释放指针。他们分配和释放 space(数据存储区域)。
space 由地址(指针值)引用。在调用 malloc
并将其 return 值赋给 arr
后,arr
指向保留的 space。当您将该指针值传递给 foo
并且 foo
将其传递给 free 时,space 不再保留。
当你在foo
中调用malloc
时,它会再次保留space。它可能会保留相同的 space、重叠的 space 或不同的 space。当您在第二次调用中使用值 returned 作为指针时,它会访问当前保留的 space.
当您访问 arr
中的剩余值时,您的程序访问了先前保留的 space。 (这并不总是会发生;一旦 space 被释放,您就不应该再使用旧指针。C 实现不会始终将旧指针视为有效,并且您的程序可能会崩溃,使用旧 space,使用不同的 space,或表现出其他行为。)
声明 arr
和 arr2
的位置与调用 malloc
和 free
的位置无关—— 指针的范围用来保存地址值,与space的保留无关。指针的 值 提供对 space 的访问。无论你通过例程调用向上或向下传递一个值,它仍然指向相同的 space.
你的代码遇到了错误,如果你想让事情正常工作,你应该注意修复它们:
int* arr = (int*)malloc(sizeof(int) * LEN);
在不检查 return 值的情况下调用 malloc!
if(!arr){
puts("heap allocation failure");
abort();
}
在函数 foo 中:
return (int*)malloc(sizeof(int) * n);
同样的问题!检查 malloc return。
从这个函数 returning 后,main 中的 arr
指针指向已释放的缓冲区!!
在这一行中:
printf("%d\t", arr[i]);
正在访问悬挂指针,已被 foo! 释放的指针!这段记忆不是你的。这将导致定位错误!或未定义的行为,如果您没有收到 SIGSIGV 信号。
在下面的代码中,有两个 int 数组在另一个函数中分配(我想检查我是否可以释放任何指针,或者只能释放本地分配的指针)。两个数组都以某种方式链接,我不明白为什么?
#include <stdlib.h>
#define LEN 10
int* foo(int*, int);
void main()
{
int* arr = (int*)malloc(sizeof(int) * LEN);
int* arr2 = foo(arr, LEN);
for (int i = 0; i < LEN; i++)
{
arr2[i] = i;
printf("%d\t", arr2[i]);
}
printf("\n");
for (int i = 0; i < LEN; i++)
{
printf("%d\t", arr[i]);
}
printf("\n");
for (int i = 0; i < LEN; i++)
{
arr[i] = i+1;
printf("%d\t", arr[i]);
}
printf("\n");
for (int i = 0; i < LEN; i++)
{
printf("%d\t", arr2[i]);
}
free(arr2);
}
int* foo(int* arr, int n)
{
free(arr);
return (int*)malloc(sizeof(int) * n);
}
输出为:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
调用foo
后,arr
指向的内存已经释放。然后您尝试访问 arr
指向的内存。
在释放内存后尝试使用内存会调用 undefined behavior。
首先尝试仅使用 arr
,然后调用 foo
并仅使用 arr2
。
这里arr和arr2指的是相同的内存位置。
malloc
和 free
不分配和释放指针。他们分配和释放 space(数据存储区域)。
space 由地址(指针值)引用。在调用 malloc
并将其 return 值赋给 arr
后,arr
指向保留的 space。当您将该指针值传递给 foo
并且 foo
将其传递给 free 时,space 不再保留。
当你在foo
中调用malloc
时,它会再次保留space。它可能会保留相同的 space、重叠的 space 或不同的 space。当您在第二次调用中使用值 returned 作为指针时,它会访问当前保留的 space.
当您访问 arr
中的剩余值时,您的程序访问了先前保留的 space。 (这并不总是会发生;一旦 space 被释放,您就不应该再使用旧指针。C 实现不会始终将旧指针视为有效,并且您的程序可能会崩溃,使用旧 space,使用不同的 space,或表现出其他行为。)
声明 arr
和 arr2
的位置与调用 malloc
和 free
的位置无关—— 指针的范围用来保存地址值,与space的保留无关。指针的 值 提供对 space 的访问。无论你通过例程调用向上或向下传递一个值,它仍然指向相同的 space.
你的代码遇到了错误,如果你想让事情正常工作,你应该注意修复它们:
int* arr = (int*)malloc(sizeof(int) * LEN);
在不检查 return 值的情况下调用 malloc!
if(!arr){
puts("heap allocation failure");
abort();
}
在函数 foo 中:
return (int*)malloc(sizeof(int) * n);
同样的问题!检查 malloc return。
从这个函数 returning 后,main 中的 arr
指针指向已释放的缓冲区!!
在这一行中:
printf("%d\t", arr[i]);
正在访问悬挂指针,已被 foo! 释放的指针!这段记忆不是你的。这将导致定位错误!或未定义的行为,如果您没有收到 SIGSIGV 信号。