1

Using what I have learned here: How to use realloc in a function in C, I wrote this program.

int data_length; // Keeps track of length of the dynamic array.
int n; // Keeps track of the number of elements in dynamic array.

void add(int x, int data[], int** test)
{

    n++;

    if (n > data_length)
    {
        data_length++;
        *test = realloc(*test, data_length * sizeof (int));
    }

    data[n-1] = x;

}

int main(void)
{

    int *data = malloc(2 * sizeof *data);

    data_length = 2; // Set the initial values.
    n = 0;

    add(0,data,&data);
    add(1,data,&data);
    add(2,data,&data);

    return 0;
}

The goal of the program is to have a dynamic array data that I can keep adding values to. When I try to add a value to data, if it is full, the length of the array is increased by using realloc.

Question

This program compiles and does not crash when run. However, printing out data[0],data[1],data[2] gives 0,1,0. The number 2 was not added to the array.

Is this due to my wrong use of realloc?

Additional Info

This program will be used later on with a varying number of "add" and possibly a "remove" function. Also, I know realloc should be checked to see if it failed (is NULL) but that has been left out here for simplicity.

I am still learning and experimenting with C. Thanks for your patience.

Community
  • 1
  • 1
Legendre
  • 3,108
  • 7
  • 31
  • 46

3 Answers3

2

Your problem is in your utilisation of data, because it points on the old array's address. Then, when your call realloc, this area is freed. So you are trying to access to an invalid address on the next instruction: this leads to an undefined behavior.

Also you don't need to use this data pointer. test is sufficient.

(*test)[n-1] = x;
md5
  • 23,373
  • 3
  • 44
  • 93
1

You don't need to pass data twice to add.

You could code

void add(int x, int** ptr)
{
  n++;
  int *data = *ptr;
  if (n > data_length) {
    data_length++;
    *ptr = data = realloc(oldata, data_length * sizeof (int));
    if (!data) 
      perror("realloc failed), exit(EXIT_FAILURE);
  }
  data [n-1] = x;
}

but that is very inefficient, you should call realloc only once in a while. You could for instance have

     data_length = 3*data_length/2 + 5;
     *ptr = data = realloc(oldata, data_length * sizeof (int));
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

Let's take a look at the POSIX realloc specification.

The description says:

If the new size of the memory object would require movement of the object, the space for the previous instantiation of the object is freed.

The return value (emphasis added) mentions:

Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space.

You can check to see if the pointer changes.

int *old;
old = *test;
*test = realloc(*test, data_length * sizeof(int));
if (*test != old)
    printf("Pointer changed from %p to %p\n", old, *test);

This possible change can interact badly because your code refers to the "same" memory by two different names, data and *test. If *test changes, data still points to the old chunk of memory.

neirbowj
  • 635
  • 5
  • 17