views:

156

answers:

7

I'm trying to figure out how to allocate a block of memory in a function and pass back a pointer to that block through one of the arguments. This is a C program. I seem to be having some trouble. Here's the code:

void foo(char *ptr)
{
     if (!(ptr = malloc(size)))
          printf("error");

     /* code here */

     printf("buffer address: %i\n", (int)buffer);
}

int main()
{
     char *ptr;
     ptr = NULL;

     foo(ptr);

     printf("buffer address: %i\n", (int)buffer);
}

And the result is:

buffer address: 142385160
buffer address: 0

but I was expecting something like:

buffer address: 142385160
buffer address: 142385160

What am I doing wrong?

+1  A: 

You need to pass a pointer to a pointer to char, like so:

void foo(char **ptr)
{
  // ...
  *ptr = result of malloc;
}

Or even better, return like so:

void char * foo(int memsize)
{

}
Mitch Wheat
+1  A: 

In your function, you reassign your local copy of the pointer. To reassign the pointer in the calling function, you need to pass it the address of the pointer, rather than the address of that the pointer points at.

void foo(char **ptr)
{
     if (!(*ptr = malloc(size)))
          printf("error");

     /* code here */

     printf("buffer address: %i\n", (int)*buffer);
}

int main()
{
     char *ptr;
     ptr = NULL;

     foo(&ptr); // pass address of your ptr, rather than it's value

     printf("buffer address: %i\n", (int)buffer);
}
Will
+5  A: 

Others have shown passing a pointer to a pointer, but a simpler option is indicated by your question:

I'm trying to figure out how to allocate a block of memory in a function and return a pointer to that block.

(Emphasis mine.)

When you think about returning something, try using it as the return value :)

char* foo()
{
    char* ptr;
    if (!(ptr = malloc(size)))
        printf("error");

    /* code here */

    printf("buffer address: %i\n", (int)ptr);
    return ptr;
}

(You might also consider returning void* instead of char*)

If you already have a return value for some other reason, then it may be appropriate to use the "pointer to a pointer" approach - but if you're not using the original value, just returning something, I believe it's worth keeping things simple if you can.

Jon Skeet
ok I changed it :)
+1, but while we're at it, I wouldn't recommend treating pointer as integer. Not sure how portable it is, but `%p` sounds better to me.
Michael Krelin - hacker
+3  A: 

Why don't you just return a pointer, much as your question states:

void* foo(void)
{
     void* ptr = malloc(size);
     if (!ptr)
          printf("error");

     /* code here */

     printf("buffer address: %p\n", ptr);
}

int main(void)
{
     char *ptr = foo();

     printf("buffer address: %p\n", (void*)ptr);
}

(Other edits I made were to make sure that all printf of pointer types used %p and were passed a void* type, either by changing the type of a variable or through an explicit cast. I also added initializations to variable declarations where appropriate.)

Charles Bailey
+1 for changing `%i` to `%p` ;-)
Michael Krelin - hacker
+3  A: 

Well, assuming that (int)buffer should be (int)ptr, you are passing the pointer by value, not reference, so changed made in the function have no effect outside.

You can either return the result:

char *foo()
{
     if (!(ptr = malloc(size)))
          printf("error");

     /* code here */

     printf("buffer address: %i\n", (int)ptr);
     return ptr;
}

int main()
{
     char *ptr;
     ptr = NULL;

     ptr = foo();

     printf("buffer address: %i\n", (int)ptr);
}

or pass the pointer by reference

void foo(char **ptr)
{
     if (!(*ptr = malloc(size)))
          printf("error");

     /* code here */

     printf("buffer address: %i\n", (int)*ptr);
}

int main()
{
     char *ptr;
     ptr = NULL;

     foo(&ptr);

     printf("buffer address: %i\n", (int)ptr);
}
developmentalinsanity
+2  A: 

Pointers are variables. All variables in C are passed by value. Observe:

void test(int i)
{
    printf("Before: %i\n", i);
    i = 0;
    printf("After:  %i\n", i);
}

int main(void)
{
    int i = 5;
    printf("Before: %i\n", i);
    test(i);
    printf("After:  %i\n", i);
}

Prints:

Before: 5
Before: 5
After:  0
After:  5

Pointers work the same way. Changing the pointer itself doesn't change the caller's pointer. The benefit of pointers is to change the contents of the pointer. You have a few options:

void foo(char **ptr)
{
    if (!(*ptr = malloc(size)))
        printf("error");

    /* code here */

    printf("buffer address: %p\n", ptr);
}

int main()
{
    char *ptr;
    ptr = NULL;

    foo(&ptr);

    printf("buffer address: %p\n", *ptr);
}

Or:

char *foo(char *ptr)
{
    if (!(ptr = malloc(size)))
        printf("error");

    /* code here */

    printf("buffer address: %p\n", ptr);
    return ptr;
}

int main()
{
    char *ptr;
    ptr = NULL;

    ptr = foo(ptr);

    printf("buffer address: %p\n", ptr);
}

Which you use depends on what foo() does. Pick the one that makes the most logical sense.

Chris Lutz
I just would remove the argument to foo from the last example, but other than that it works! thanks!
A: 

One more simplification could be :

void *fun() { return(malloc(sizeof(char))); }

int main() { char *foo = (char *) fun(); printf("\n%p\n",foo); }

Furquan