C Programming: malloc() inside another function

107,664

Solution 1

You need to pass a pointer to a pointer as the parameter to your function.

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size) == NO_ERROR)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char **ptr, unsigned int size) 
{ 
    signed char status = NO_ERROR; 
    *ptr = NULL; 

    *ptr = (unsigned char*)malloc(size); 

    if(*ptr== NULL) 
    {
        status = ERROR; 
        free(*ptr);      /* this line is completely redundant */
        printf("\nERROR: Memory allocation did not complete successfully!"); 
    } 

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr)); 

    return status; 
} 

Solution 2

How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?

Ask yourself this: if you had to write a function that had to return an int, how would you do it?

You'd either return it directly:

int foo(void)
{
    return 42;
}

or return it through an output parameter by adding a level of indirection (i.e., using an int* instead of int):

void foo(int* out)
{
    assert(out != NULL);
    *out = 42;
}

So when you're returning a pointer type (T*), it's the same thing: you either return the pointer type directly:

T* foo(void)
{
    T* p = malloc(...);
    return p;
}

or you add one level of indirection:

void foo(T** out)
{
    assert(out != NULL);
    *out = malloc(...);
}

Solution 3

If you want your function to modify the pointer itself, you'll need to pass it as a pointer to a pointer. Here's a simplified example:

void allocate_memory(char **ptr, size_t size) {
    void *memory = malloc(size);
    if (memory == NULL) {
        // ...error handling (btw, there's no need to call free() on a null pointer. It doesn't do anything.)
    }

    *ptr = (char *)memory;
}

int main() {
   char *data;
   allocate_memory(&data, 16);
}

Solution 4

You need to pass the pointer by reference, not by copy, the parameter in the function alloc_pixels requires the ampersand & to pass back out the address of the pointer - that is call by reference in C speak.

main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     

}

signed char alloc_pixels(unsigned char **ptr, unsigned int size)
{
    signed char status = NO_ERROR;
    *ptr = NULL;

    *ptr = (unsigned char*)malloc(size);

    if((*ptr) == NULL)
    {
        status = ERROR;
        /* free(ptr);
        printf("\nERROR: Memory allocation did not complete successfully!"); */
    }

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr));

    return status;
}

I have commented out the two lines free(ptr) and "ERROR: ..." within the alloc_pixels function as that is confusing. You do not need to free a pointer if the memory allocation failed.

Edit: After looking at the msdn link supplied by OP, a suggestion, the code sample is the same as earlier in my answer.... but...change the format specifier to %u for the size_t type, in the printf(...) call in main().

main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %u bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     

}

Solution 5

As mentioned in the other answers, we need a pointer to the pointer. But why?

We need to pass the value by a pointer in order to be able to modify the value. If you want to modify an int, you need to pass it by the int*.

In this question, the value we want to modify is a pointer int* (pointer changed from NULL to the address of the allocated memory), so we need to pass a pointer to the pointer int**.

By doing followed, pInt inside foo(int*) is a copy of the argument. When we allocate memory to the local variable, the one in the main() is intact.

void foo(int* pInt)
{
   pInt = malloc(...);
}
int main()
{
   int* pInt;
   foo(pInt);
   return 0;
}

So we need a pointer to pointer,

void foo(int** pInt)
{
   *pInt = malloc(...);
}
int main()
{
   int* pInt;
   foo(&pInt);
   return 0;
}
Share:
107,664

Related videos on Youtube

HaggarTheHorrible
Author by

HaggarTheHorrible

Updated on July 05, 2022

Comments

  • HaggarTheHorrible
    HaggarTheHorrible almost 2 years

    I need help with malloc() inside another function.

    I'm passing a pointer and size to the function from my main() and I would like to allocate memory for that pointer dynamically using malloc() from inside that called function, but what I see is that.... the memory, which is getting allocated, is for the pointer declared within my called function and not for the pointer which is inside the main().

    How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?


    I have written the following code and I get the output as shown below.

    SOURCE:

    int main()
    {
       unsigned char *input_image;
       unsigned int bmp_image_size = 262144;
    
       if(alloc_pixels(input_image, bmp_image_size)==NULL)
         printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
       else
         printf("\nPoint3: Memory not allocated");     
       return 0;
    }
    
    signed char alloc_pixels(unsigned char *ptr, unsigned int size)
    {
        signed char status = NO_ERROR;
        ptr = NULL;
    
        ptr = (unsigned char*)malloc(size);
    
        if(ptr== NULL)
        {
            status = ERROR;
            free(ptr);
            printf("\nERROR: Memory allocation did not complete successfully!");
        }
    
        printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));
    
        return status;
    }
    

    PROGRAM OUTPUT:

    Point1: Memory allocated ptr: 262144 bytes
    Point2: Memory allocated input_image: 0 bytes
    
  • Carl Norum
    Carl Norum about 14 years
    It's safe to call free() on a null pointer, what is that comment about?
  • Matti Virkkunen
    Matti Virkkunen about 14 years
    @Carl Norum: It's safe, but pointless. IMO, code that doesn't do anything only leads to confusion for people who end up reading it later and should be avoided.
  • James Morris
    James Morris about 14 years
    @Matti Virkkunen: Telling people to not call free on a NULL pointer is pointless and misinformation - you're causing people to become confused when they see code that goes against your advice.
  • James Morris
    James Morris about 14 years
    <S>Why are you calling free in a conditional code block that is guaranteed to have a NULL pointer!?!?</S> The free(*ptr) will when called from main() try to free input_image which was ummm, the term evades me... not dynamically allocated.
  • Matti Virkkunen
    Matti Virkkunen about 14 years
    @James Morris: Fine, fine... like the wording better now?
  • Donal Fellows
    Donal Fellows about 14 years
    @Carl: I've encountered (not very nice) C libraries that crashed if asked to free(NULL); so it's good to avoid anyway. (No, I don't remember which. It was quite a while ago.)
  • jamesdlin
    jamesdlin about 14 years
    @Donal Fellows: Those C libraries are non-conforming, then. The standard requires free(NULL) to do nothing.
  • Matti Virkkunen
    Matti Virkkunen about 14 years
    @Donal Fellows: Sounds like a horribly broken standard library to me... must have really been a while ago
  • HaggarTheHorrible
    HaggarTheHorrible about 14 years
    and @James: I did what was suggested by Mark and Matti, but this time both my _mize(input_image) in my main() and _msize(**ptr) in my alloc_pixels(...) function are returning the size as 0. Whereas if it is _msize(*ptr) (single *) returns 262144. ?
  • HaggarTheHorrible
    HaggarTheHorrible about 14 years
    @All here :) I did what was suggested by Mark and Matti, but this time both my _mize(input_image) in my main() and _msize(**ptr) in my alloc_pixels(...) function are returning the size as 0. Whereas if it is _msize(*ptr) (single *) returns 262144. ?
  • Matti Virkkunen
    Matti Virkkunen about 14 years
    @vikramtheone: I don't see what the problem is, the return values seem to be correct.
  • HaggarTheHorrible
    HaggarTheHorrible about 14 years
    @Matti: How can I find out the size of memory just allocated using the input_image pointer? Why does _msize(input_image) return a 0 and not the size of memory?
  • Matti Virkkunen
    Matti Virkkunen about 14 years
    @vikramtheone: Because inside alloc_pixels, ptr is a pointer to the stack of the calling function and not the heap. You need to dereference ptr by doing *ptr to get to the heap address.
  • HaggarTheHorrible
    HaggarTheHorrible about 14 years
    I understand what wrong I was doing. There is however one issue still not solved. When I make these changes and use _msize(input_image); in my main(), the _msize(...) returns a 0. At the same time for _msize(*ptr); in the other function, I get the size as 262144. What's going wrong here? I have no clue.
  • Mark Ransom
    Mark Ransom about 14 years
    Thanks for giving the explanation I was too rushed to provide.
  • Mark Ransom
    Mark Ransom about 14 years
    @James Morris, I just copied the code that was posted in the question and made the minimal number of changes. I didn't want to get caught up in a distraction to the main point.
  • Mark Ransom
    Mark Ransom about 14 years
    @vikramtheone, sorry I was a bit rushed and didn't make this answer as complete as it should have been. I've edited it to be more complete. I hope you can see how it is different than your original code and why it must be this way.
  • Tim Post
    Tim Post about 14 years
    +1, I love everything but the assertion, however its fine for such a simple demonstration.
  • Donal Fellows
    Donal Fellows about 14 years
    @Matti: It was back in the early '90s, and was considered an old std-lib then. Of course, back then we also had all the ridiculous nastiness of far pointers, memory models and other things like that, which I'm convinced still leave their mark in standards today (such as in the lack of a guarantee that pointers to data and pointers to functions are the same size).
  • Donal Fellows
    Donal Fellows about 14 years
    In short, life is much better now. :-)
  • Donal Fellows
    Donal Fellows about 14 years
    I like the assertion; it is a part of the contract for the function which the caller should get systematically correct. Of course, even more subtle code might make a NULL out allowable, having it correspond to an optional out-parameter. But that's not what is needed for alloc_pixels; the question does not require such sophistication.
  • t0mm13b
    t0mm13b about 14 years
    @vikramtheone: can you show the function prototype for _msize(...) please? Amend your question to highlight that...
  • HaggarTheHorrible
    HaggarTheHorrible about 14 years
    Never mind, it works fine now :) It was a late-late night work and my mind had all become fuzzy and I forgot to change the main(). I was not sending the address of input_image when I calling the alloc_memory(...) in main().
  • William Everett
    William Everett over 10 years
    Is it safe to free(*out) inside the calling function (main in this case)?
  • jamesdlin
    jamesdlin over 10 years
    @Pinyaka: It's safe for the caller to call free() on the resulting pointer (how else would the caller free the allocated memory?). However, the caller would either be doing T* out = foo(); (in the first form) or T* out; foo(&out); (in the second form). In both cases, the caller would have to call free(out), not free(*out).
  • Zeeshan
    Zeeshan about 8 years
    I tried the same thing on MSVS, but it did not work. input_image remains 'bad pointer'. What could be the reason?
  • Mark Ransom
    Mark Ransom about 8 years
    @ZeeshanMahmood probably a typo. It's easy to miss the * at the beginning of the assignment.