动态内存访问仅在函数内部工作

Dynamic memory access only works inside function

提问人: 提问时间:9/14/2016 最后编辑:5 revs, 2 users 99%Lundin 更新时间:1/23/2019 访问量:5202

问:

此问题旨在用作本常见问题解答的规范副本:

我在函数内动态分配数据,一切正常,但仅限于进行分配的函数内部。当我尝试在函数外部使用相同的数据时,我遇到崩溃或其他意外的程序行为。

这是 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_arraycreate_array0 1 2 3 4main

这是什么原因?

c malloc 参数 dynamic-memory-allocation 按值传递

评论

5赞 Jean-François Fabre 9/14/2016
我差点因为你犯了这么愚蠢的错误而投了反对票:)
1赞 Lundin 9/14/2016
@Jean-FrançoisFabre 不幸的是,我还没有找到一种方法来使这个问题成为社区维基,只有答案。我已经戳了模组,所以希望它能很快转换为社区维基。
2赞 LPs 9/14/2016
我认为可以更好地托管在 Documentation Beta 上。
4赞 Lundin 3/17/2017
@RestlessC0bra 误报 = 工具错误 = 工具损坏。VS2015是一个C++编译器。在C模式下,它非常坏,每个人都知道。它不符合C标准,也不符合1999年以前的C标准,也不符合古老的C90/ANSI标准。众所周知,抱怨完美的C代码,因为Microsoft认为只有他们才有权决定哪些语言特性是好的,哪些是坏的,而不是C标准委员会。
1赞 Matthieu 5/18/2019
@Lundin如果可以的话,我会给你赏金!

答:

19赞 3 revs, 2 users 87%Lundin #1

此错误的原因是该函数使用的是一个局部变量,仅存在于该函数内部。从中获取的分配的内存地址仅存储在此局部变量中,永远不会返回给调用方。datacreate_arraymalloc


请看这个简单的例子:

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

在这里,变量的副本作为参数存储在函数内部。这称为按值传递ax

修改时,仅更改该局部变量。调用方中的变量保持不变,并且由于未初始化,因此它将包含“垃圾”,无法可靠地使用。xaa


指针也不例外。在您的示例中,指针变量按值传递给函数。函数内部的指针是本地副本,分配的地址永远不会传递回调用方。datadatamalloc

因此,调用方中的指针变量保持未初始化状态,因此程序崩溃。此外,该函数还造成了内存泄漏,因为在该函数执行后,程序中不再有任何指针跟踪该分配的内存块。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);
}

任何一种形式都可以。