Talaria
Talaria

Reputation: 228

Is there potential data corruption when a struct with an array of pointers is malloc'd

I want to take in three arbitrary length buffers of doubles. Below is a short example

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;
}

My concern is that if I malloc Data in the manner above I run the risk of corrupt data. If I allocate memory on the heap for an array of pointers to double buffers (or essentially an arbitrarily sized two-dimensional array of doubles) without knowing the size, is the data protected in any way? I feel like it runs the possibility of overwritten data. Am I correct in this thinking? This compiles and prints, but I'm not sure I trust it in a much larger scale implementation.

Upvotes: 2

Views: 494

Answers (2)

Peter Schneider
Peter Schneider

Reputation: 1701

As long as you do not assign wrong values, there is no data corruption. You have to be aware, where the data lives and how long it's valid. For example:

/* !!!! 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;
}

This would be a bad idea:

  • data is heap-allocated and "lives" until you call free
  • bar1..3 is stack-allocated and only lives inside of initData()
  • data->foo points to bar1..3 and is only valid inside initData()
  • the printf-calls might work (haven't tested) but it is broken code

Getting this right is the hardest task with C. When you use linux for development, you should take a look into valgrind to catch those type of bugs (the one in my example is obvious but it can get realy hard)

Upvotes: 2

John Bollinger
John Bollinger

Reputation: 181149

Certainly the malloc() itself does not contribute to the risk of data corruption. Whatever risk there is would be at least as great if the struct in question were an automatic variable allocated on the stack.

What you seem really to be asking about is the data structure itself, and basically pointers in general. Yes, if you have a pointer then it is possible to attempt an invalid memory access via that pointer, outside the bounds of the object to which the pointer points. C provides no protection against such attempts; it addresses the issue by declaring that the behavior of a program that attempts such an action is undefined.

It is incumbent on the programmer to ensure that his program does not attempt such an action. For pointers to arrays, one generally approaches that problem either by keeping track separately of the length of the pointed-to array, or by marking the end of the array with a sentinel value that cannot appear as normal data.

Upvotes: 1

Related Questions