此问题旨在用作此常见问题解答的规范副本:
我在一个函数内动态分配数据,一切运行良好,但只在分配发生的函数内部。当我尝试在函数外部使用相同的数据时,我会遇到崩溃或其他意外的程序行为。
这是MCVE:
#include <stdlib.h>
#include <stdio.h>
void create_array (int* data, int size)
{
data = malloc(sizeof(*data) * size);
for(int i=0; i<size; i++)
{
data[i] = i;
}
print_array(data, size);
}
void print_array (int* data, int size)
{
for(int i=0; i<size; i++)
{
printf("%d ", data[i]);
}
printf("\n");
}
int main (void)
{
int* data;
const int size = 5;
create_array(data, size);
print_array(data, size); // crash here
free(data);
}
每当从print_array
函数内部调用create_array
时,我得到预期的输出0 1 2 3 4
,但是当我从main
调用它时,我的程序崩溃了。
这是什么原因?
答案 0 :(得分:13)
此错误的原因是data
函数使用的create_array
是仅存在于该函数内的局部变量。从malloc
获取的已分配内存地址仅存储在此本地变量中,并且永远不会返回给调用者。
考虑这个简单的例子:
void func (int x)
{
x = 1;
printf("%d", x);
}
...
int a;
func(a);
printf("%d", a); // bad, undefined behavior - the program might crash or print garbage
此处,变量a
的副本存储在函数内部,作为参数x
。这称为按值传递。
修改x
时,只更改该局部变量。调用者中的变量a
保持不变,并且由于a
未初始化,因此它将包含“垃圾”并且无法可靠地使用。
指针对这个按值传递规则也不例外。在您的示例中,指针变量data
通过值传递给函数。函数内的data
指针是本地副本,来自malloc
的指定地址永远不会传递回调用者。
因此调用者中的指针变量保持未初始化状态,因此程序崩溃。此外,create_array
函数还创建了内存泄漏,因为在该函数执行之后,程序中不再有任何指针跟踪分配的内存块。
有两种方法可以修改函数以按预期工作。通过将局部变量的副本返回给调用者:
int* create_array (int size)
{
int* data = malloc(sizeof(*data) * size);
for(int i=0; i<size; i++)
{
data[i] = i;
}
print_array(data, size);
return data;
}
int main (void)
{
int* data;
const int size = 5;
data = create_array(size);
print_array(data, size);
}
或将地址传递给调用者的指针变量并直接写入调用者变量:
void create_array (int** data, int size)
{
int* tmp = malloc(sizeof(*tmp) * size);
for(int i=0; i<size; i++)
{
tmp[i] = i;
}
*data = tmp;
print_array(*data, size);
}
int main (void)
{
int* data;
const int size = 5;
create_array(&data, size);
print_array(data, size);
}
两种形式都没问题。