tags:

views:

2035

answers:

5

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.

+6  A: 

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))

terminus
+26  A: 

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;
}
Nils Pipenbrinck
Can I just say, please don't cast the return value of malloc? It is not required and can hide errors.
freespace
@freespace, that's a habit I've developed over the years. Every one and then I have to send my code through static code analysis tools, and they complain about not casting pointers.
Nils Pipenbrinck
Sorry about leaving you hanging without a reply: there is no good way to find replies in comments unless I poll all my comments :)I have left the answer in http://stackoverflow.com/questions/108768/needless-pointer-casts-in-c#108781
freespace
@freespace, I know - hope a feature to notify via comments will be added one day.
Nils Pipenbrinck
A: 

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.

Bill K
+3  A: 

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)
Andrew Stein
+1  A: 

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.

Alexander