1

I have written the folowing code in C:

#include <stdio.h>
#include <stdlib.h>

int func(int n, int * data){
  for(int i = 1; i <= n; i++){
    data = realloc(data, i * sizeof(int));
    data[i - 1] = i;
  }
  return 0;
}

int main(void){

  int numb = 10;
  int * array = calloc(1, sizeof(int));
  func(numb, array);

  for(int j = 0; j < numb; j++){
    printf("%d \t", array[j]);
  }

  free(array);
  return 0;
}

On the first computer the output is as expected:

1 2 3 4 5 6 7 8 9 10

Now if I compile and run the same program on another computer, it outputs random integer values. What am I missing here? What do I do wrong? Why does the very same program have a different behaviour on different computers?

3 Answers3

3

The behavior of this program is undefined. If it prints out what you expect on any computer, it's purely by coincidence.

  int * array = calloc(1, sizeof(int));
  func(numb, array);

You're passing array by value here, meaning whatever func does to it is invisible to the outer scope. Note that realloc is not guaranteed to return the same pointer, so you need to expect that array will be changed during the course of the call. Try passing a pointer to array instead.

int func(int n, int ** data){
  for(int i = 1; i <= n; i++){
    *data = realloc(*data, i * sizeof(int));
    (*data)[i - 1] = i;
  }
  return 0;
}

...

    func(numb, &array);
Jon Reeves
  • 2,426
  • 3
  • 14
1

Following Ian Abbot comment, the minimal correction you can do is having func() return the newly allocated block:

#include <stdio.h>
#include <stdlib.h>

int * func(int n, int * data)  // <-- Notice the * in the return value
{
  for(int i = 1; i <= n; i++){
    data = realloc(data, i * sizeof(int));
    data[i - 1] = i;
  }
  return data; // <-- We return a pointer to the newly allocated memory block
}

int main(void)
{
  int numb = 10;
  int * array = calloc(1, sizeof(int));
  array = func(numb, array); // <-- reassign to array (same pattern as realloc)

  for(int j = 0; j < numb; j++){
    printf("%d \t", array[j]);
  }

  free(array);
  return 0;
}

In this way you are sure that if realloc() changed the position of the memory block it gets updated in array.

Costantino Grana
  • 3,132
  • 1
  • 15
  • 35
0

Your program has undefined behaviour. So, it is possible that it has different behaviours even in the same computer... Let me explain:

#include <stdio.h>
#include <stdlib.h>

int func(int n, int * data){
  for(int i = 1; i <= n; i++){
    // HERE, YOU CHANGE THE VALUE OF data FOR THE NEW
    // VALUE RETURNED BY REALLOC.  As the value ov array
    // was copied on entry, it is not known outside of
    // func()
    data = realloc(data, i * sizeof(int));
    data[i - 1] = i;
  }
  return 0;
  // AFTER THIS POINT THE ORIGINAL (the passed in value
  // to func() is not valid anymore
}

int main(void){

  int numb = 10;
  int * array = calloc(1, sizeof(int));
  func(numb, array);
  // at this point, the value of array is not valid,
  // in case the value realloc() has returned inside
  // func() has changed.

  for(int j = 0; j < numb; j++){
    printf("%d \t", array[j]);
  }

  // THIS IS ALSO INCORRECT.
  free(array);
  return 0;
}

A workaround to your problem is that you return the new value back (the one returned by calloc()), as in

#include <stdio.h>
#include <stdlib.h>

int *func(int n, int * data){
  for(int i = 1; i <= n; i++){
    data = realloc(data, i * sizeof(int));
    data[i - 1] = i;
  }
  return data;
}

int main(void){

  int numb = 10;
  int * array = calloc(1, sizeof(int));
  // now array continues to be bvalid after the call to func().
  array = func(numb, array);

  for(int j = 0; j < numb; j++){
    printf("%d \t", array[j]);
  }

  free(array);
  return 0;
}

By the way, in order to be optimum, and as you know the final value that i will take in func() (n), you should write func() to make only one call to realloc() and this will be faster than reallocating once per value.

int *func(int n, int *data) {
  data = realloc(data, n * sizeof *data);
  for (int i = 1; i <= n; i++)
    data[i-1] = i;
  return data;
}
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31