当具有指针数组的结构是malloc时,是否存在潜在的数据损坏

时间:2015-11-19 16:41:17

标签: c arrays pointers malloc heap

我想要三个任意长度的双倍缓冲区。以下是一个简短的例子

struct Data
{
  double *foo[3];
};

int main(void)
{
  double bar1[] = {1.0, 2.0, 3.0};
  double bar2[] = {1.0, 2.0, 3.0, 4.0};
  double bar3[] = {1.0, 2.0, 3.0, 4.0, 5.0};

  struct Data *data = (struct Data*)malloc(sizeof(struct Data));

  data->foo[0] = bar1;
  data->foo[1] = bar2;
  data->foo[2] = bar3;

  printf("%lf %lf %lf\n", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
  printf("%lf %lf %lf %lf\n", data->foo[1][0], data->foo[1][1], 
  data->foo[1][2], data->foo[1][3]);
  printf("%lf %lf %lf %lf %lf\n", data->foo[2][0], data->foo[2][1], 
  data->foo[2][2], data->foo[2][3], data->foo[2][4]);

  return 0;
}

我担心的是,如果我以上述方式使用malloc Data,则会冒着损坏数据的风险。如果我在堆上为一个指向双缓冲区(或基本上是任意大小的二维双精度数组)的指针数组分配内存而不知道大小,那么数据是否受到任何保护?我觉得它有可能覆盖数据。我这个想法是否正确?这会编译和打印,但我不确定我是否会在更大规模的实现中信任它。

2 个答案:

答案 0 :(得分:2)

只要您没有分配错误的值,就不会有数据损坏。您必须了解数据的存在位置以及数据的有效期。例如:

/* !!!! broken code ahead !!!! */
struct Data
{
  double *foo[3];
};

void initData(struct Data* data) {
  double bar1[] = {1.0, 2.0, 3.0};
  double bar2[] = {1.0, 2.0, 3.0, 4.0};
  double bar3[] = {1.0, 2.0, 3.0, 4.0, 5.0};
  data->foo[0] = bar1;
  data->foo[1] = bar2;
  data->foo[2] = bar3;
}

int main(void)
{
  struct Data *data = (struct Data*)malloc(sizeof(struct Data));
  initData(data);

  printf("%lf %lf %lf\n", data->foo[0][0], data->foo[0][1], data->foo[0][2]);
  printf("%lf %lf %lf %lf\n", data->foo[1][0], data->foo[1][1], 
  data->foo[1][2], data->foo[1][3]);
  printf("%lf %lf %lf %lf %lf\n", data->foo[2][0], data->foo[2][1], 
  data->foo[2][2], data->foo[2][3], data->foo[2][4]);

  return 0;
}

这是一个坏主意:

  • data是堆分配的,"生活"直到你拨打free
  • bar1..3是堆叠分配的,只存在于initData()
  • data->foo指向bar1..3,仅在initData()
  • 内有效
  • printf - 调用可能有效(未经过测试)但是代码已损坏

正确使用C是最困难的任务当你使用linux进行开发时,你应该看看valgrind来捕获那些类型的bug(我的例子中的那个很明显,但它可以真的很难)

答案 1 :(得分:1)

当然malloc()本身不会导致数据损坏的风险。如果所讨论的结构是在堆栈上分配的自动变量,那么无论风险如何都至少一样好。

你真正要问的是数据结构本身,基本上是指针。是的,如果你有一个指针,那么可以通过指针在指针指向的对象边界之外尝试无效的内存访问。 C不提供此类尝试的保护;它通过声明尝试此类操作的程序的行为未定义来解决该问题。

程序员有责任确保他的程序不会尝试这样的行动。对于指向数组的指针,通常可以通过分别跟踪指向数组的长度来跟踪该问题,或者通过使用不能作为普通数据显示的标记值来标记数组的结尾。