1

I don't understand why this first version of my code is working and the second isn't.

First version :

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

void procedure(int *t){
    t = (int*)realloc(t, 4*sizeof(int));

    t[3] = 4;
}


int main()
{
    int *var;
    var = (int*)malloc(sizeof(int));

    procedure(var);

    printf("%d\n\n", var[3]);
}

Second version:

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

void procedure(int *t){
    t = (int*)malloc(4*sizeof(int));

    t[3] = 4;
}


int main()
{
    int *var = NULL;


    procedure(var);

    printf("%d\n\n", var[3]);
}

In the second version, var is still a NULL pointer after the procedure execution. Why?

4 Answers4

1

You should remember that everything in C is passed by value, even pointers. So let's start with the second example.

You set var in main to NULL. Then you copy the address in it (NULL) to the varaible t in procedure. You proceed to malloc memory and assign that address to t. But t is just a copy of var, and any change to t is not reflected in var. Outside of procedure, the pointer retains the NULL address and the call to printf with var[3] is undefined behavior.

The second case features the same symptoms, but with a twist. realloc doesn't have to return a different address. It's memory allocator aware, so if it can just "extend" the block of memory being pointed to, it will. That's what you see happening. The call to realloc extends the memory and returns the same address it was given. So by sheer coincidence, t and var end up pointing to the same location, still.

That's why the modification to t[3] is visible using var[3]. This is not a behavior you can rely on.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

In the second version of your code, you are simply passing the address var points to. In procedure(...), you have, in essence, declared an int-pointer and on the first line (the malloc line), you are assigning that pointer a value. var is not updated with this value, because var is a separate entity entirely.

Essentially, you might as well be doing the following:

int *var = NULL;
int *t = malloc(4*sizeof(int));
t[3]=4;
printf("%d\n\n", var[3]);

var is never reassigned to anything, so var will always be null.

This can be corrected, though, like so:

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

void procedure(int **t){
    *t = malloc(4*sizeof(int));

    (*t)[3] = 4;
}


int main()
{
    int *var = NULL;

    procedure(&var);

    printf("%d\n\n", var[3]);
}

You can view this working at: https://ideone.com/aTY9Ok

EDIT: Also, it is worth noting that you should be doing the same thing in your first version because realloc(...) might return a different address than var which could lead to a memory leak.

Spencer D
  • 3,376
  • 2
  • 27
  • 43
0

If to read the description of the function realloc in the C Standard then you will know that

Returns 4 The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

So in the first case it occured such a way that the value of the pointer was not changed. Though to rely on this results in undefined behavior.

In the second case when the standard function malloc was used the new extent with a different address was allocated. So the original pointer does not points to the new extent of memory because it was passed to the function by value.

Thus in the both cases the original pointer was not changed. The difference is that in the first case the system can just enlarge the memory extent keeping its original address unchanged while in the second case the system allocates a new extent with a different address.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Let's take it step by step here.

  • int *t means the "address of t", meaning that it is simply a number
  • Passing any number into a function means you are COPYING that data into that function (NOT LINKING IT)
  • Which means that number can change inside the function, but not outside (because it is a copy)
  • Even though t is a pointer, that pointer is still a number... setting equal to something else (ie. t = (int*)malloc(4*sizeof(int));) does not mean the value of var changed. (Because again, t is a copy of var)
Dellowar
  • 3,160
  • 1
  • 18
  • 37