Question

A few days ago I had to use C and when working with pointers I got a little surprise.

An example in C:

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

void GetPointer(int* p) {
  p = malloc( sizeof(int) );
  if(p) {
    *p = 7;
     printf("IN GetPointer: %d\n",*p);
  } else {
    printf("MALLOC FAILED IN GetPointer\n");
  }
}

void GetPointer2(int* p) {
  if(p) {
    *p = 8;
     printf("IN GetPointer2: %d\n",*p);
  } else {
    printf("INVALID PTR IN GetPointer2");
  }
}

int* GetPointer3(void) {
  int* p = malloc(sizeof(int));
  if(p) {
    *p = 9;
    printf("IN GetPointer3: %d\n",*p);
  } else {
    printf("MALLOC FAILED IN GetPointer3\n");
  }
  return p;
}

int main(int argc, char** argv) {
  (void) argc;
  (void) argv;
  int* ptr = 0;
  GetPointer(ptr);
  if(!ptr) {
    printf("NOPE\n");
  } else {
    printf("NOW *PTR IS: %d\n",*ptr);
    free(ptr);
  }

  int* ptr2 = malloc(sizeof(int));
  GetPointer2(ptr2);
  if(ptr2) {
    printf("NOW *PTR2 IS: %d\n",*ptr2);
    free(ptr2);
  }

  int* ptr3 = GetPointer3();
  if(ptr3) {
    printf("NOW *PTR3 IS: %d\n",*ptr3);
    free(ptr3);
  }
  return 0;
}

The output:

IN GetPointer: 7
NOPE
IN GetPointer2: 8
NOW *PTR2 IS: 8
IN GetPointer3: 9
NOW *PTR3 IS: 9

In this example, the first pointer will only have "value" inside the GetPointer method. Why using malloc inside lasts only for the lifetime of the method?

I tried this in C++ and got the same behaviour. I thought it would retain its value, but no. I found a way through, though:

void GetPointer(int*& p) {
  p = new int;
  if(p) {
    *p = 7;
     printf("IN GetPointer: %d\n",*p);
  } else {
    printf("MALLOC FAILED IN GetPointer\n");
  }
}

In C I can't do this trick. Is there a way to do the same in C or I have to be careful and "malloc" the pointer before attempting to give it a value?

Was it helpful?

Solution

If you want to reassign what the pointer points to in C, you have to use int**, ie a pointer to a pointer.

That is because pointers are copied by value as arguments, so if want the change made in the pointers pointee to be visible outside the scope of the function, you need another level of indirection.

OTHER TIPS

this

void GetPointer(int* p) {
  p = malloc( sizeof(int) );
  if(p) {
    *p = 7;
     printf("IN GetPointer: %d\n",*p);
  } else {
    printf("MALLOC FAILED IN GetPointer\n");
  }
}

does absolutely nothing part from creating a memory leak.

the reason it doesn't do anything is that you pass a copy of the pointer to the function (int* p), if you want to change what p points to you need to pass the address of the pointer instead.

void GetPointer(int** p)
void GetPointer(int** pp) {
    int *p = malloc( sizeof(int) );
    if(p) {
        *p = 7;
        printf("IN GetPointer: %d\n",*p);
    } else {
        printf("MALLOC FAILED IN GetPointer\n");
    }
    *pp = p;
}

In void GetPointer(int* p) you are losing the pointer pointing to the dynamic memory as soon as you exit the function block.

Try using pointer to pointer approach:

GetPointer(int ** p) {
  *p = malloc( sizeof(int) );
  if(*p) {
    **p = 7;
     printf("IN GetPointer: %d\n",**p);
  } else {
    printf("MALLOC FAILED IN GetPointer\n");
  }
}
  p = malloc( sizeof(int) );

malloc( sizeof(int)); will return a pointer which is then assigned to p. But p is local to GetPointer,since the pointer itself is passed by value to it.

     +----+
     |    |
  xx +----+  malloc returns this block

     +----+
     |    |
  xx +----+  local variable p is assigned this block

     +----+
     |  7 |
  xx +----+  p modifies value of this block

Function ends and so does p leaving behind a memory leak

     +----+
     |  7 |
  xx +----+  No one points to it anymore

For GetPointer2 and GetPointer3 you do a malloc,

     +----+
     |    |
  yy +----+  malloc returns some other block

For the first call to GetPointer, you need to pass in a pointer to a pointer to an int. (unlike C++, which allows reference passing with the & operator in the function signature, C always passes things in by value, which means that your code is passing in a copy of ptr into the GetPointer function.) You need to pass in the address of that pointer (i.e. the location in memory where the pointer ptr is stored so that code inside the GetPointer method can put something in that location, thereby modifying ptr itself.

i.e. the call should be:

GetPointer(&ptr);

and the functions should look like:

void GetPointer(int** p) {
  *p = malloc( sizeof(int) );
  if(*p) {
    **p = 7;
     printf("IN GetPointer: %d\n",**p);
  } else {
    printf("MALLOC FAILED IN GetPointer\n");
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top