Bee
Bee

Reputation:

Malloc inside a function call appears to be getting freed on return?

I think I've got it down to the most basic case:

int main(int argc, char ** argv) {
  int * arr;

  foo(arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int * arr) {
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
}

The output is this:

> ./a.out 
 car[3]=-1869558540
 a.out(4100) malloc: *** error for object 0x8fe01037: Non-aligned pointer
                         being freed
 *** set a breakpoint in malloc_error_break to debug
>

If anyone can shed light on where my understanding is failing, it'd be greatly appreciated.

Upvotes: 16

Views: 19725

Answers (5)

Alexander
Alexander

Reputation: 9370

Since your are passing the pointer by value, the arr pointer inside main isn't pointing to the allocated memory. This means two thing: you've got yourself a memory leak (NO, the memory isn't freed after the function foo completes), and when you access the arr pointer inside main you are accessing some arbitrary range of memory, hence you don't get 3 printed out and hence free() refuses to work. You're lucky you didn't get a segmentation fault when accessing arr[3] inside main.

Upvotes: 1

Nils Pipenbrinck
Nils Pipenbrinck

Reputation: 86423

You pass the pointer by value, not by reference, so whatever you do with arr inside foo will not make a difference outside the foo-function. As m_pGladiator wrote one way is to declare a reference to pointer like this (only possible in C++ btw. C does not know about references):

int main(int argc, char ** argv) {
  int * arr;

  foo(arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int * &arr ) {
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
}

Another (better imho) way is to not pass the pointer as an argument but to return a pointer:

int main(int argc, char ** argv) {
  int * arr;

  arr = foo();
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

int * foo(void ) {
  int * arr;
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
  return arr;
}

And you can pass a pointer to a pointer. That's the C way to pass by reference. Complicates the syntax a bit but well - that's how C is...

int main(int argc, char ** argv) {
  int * arr;

  foo(&arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int ** arr ) {
  (*arr) = (int*) malloc( sizeof(int)*25 );
  (*arr)[3] = 69;
}

Upvotes: 47

Andrew Stein
Andrew Stein

Reputation: 13190

foo receives a local copy of the int pointer, alloactes memory to it and leaks that memory when it goes out of scope.

One way to fix this to get foo to return the pointer:

int * foo() {
  return (int*) malloc( sizeof(int)*25 );
}

int main() {
    int* arr = foo();
}

Another is to pass foo a pointer to a pointer

void foo(int ** arr) {
   *arr = malloc(...);
}

int main() {
    foo(&arr);
}

In C++ it is simpler to modify foo to accept a reference to a pointer. The only change you need in C++ is to change foo to

void foo(int * & arr)

Upvotes: 3

Bill K
Bill K

Reputation: 62789

You cannot change the value of your argument (arr) if it's not passed in by reference (&). In general, you would want to return the pointer, so your method should be:

arr=foo();

It's bad juju to try to reassign arguments; I don't recommend the (&) solution.

Upvotes: 0

terminus
terminus

Reputation: 14512

You've allocated arr in foo, but that pointers value is stored in the call stack. If you want to do this, do it like this:

void foo( int ** arr) {
    *arr = (int *)malloc( sizeof(int) * 25 );
    (*arr)[3] = 69;
}

And in main, simply pass a pointer to foo (like foo(&arr))

Upvotes: 6

Related Questions