该问题旨在作为此常见问题的规范重复使用:

我正在函数内部动态分配数据,并且一切正常,但仅在发生分配的函数内部。当我尝试在函数外使用相同的数据时,出现崩溃或其他程序意外行为。

这是一个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进行调用时,则会导致程序崩溃。

这是什么原因呢?

最佳答案

造成此错误的原因是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);
}


两种形式都可以。

关于c - 动态内存访问仅在功能内部起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55728950/

10-11 22:13
查看更多