Hello, OnlineGDB Q&A section lets you put your programming query to fellow community users. Asking a solution for whole assignment is strictly not allowed. You may ask for help where you are stuck. Try to add as much information as possible so that fellow users can know about your problem statement easily.

Confusion on malloc() function

+3 votes
asked Mar 12 by AustinTorresLopez (150 points)
My confusion occurs from the term "dynamic memory."

I have understood this so far:

i have a pointer, x, and i want to allocate memory to the heap (not stack). this means, the memory will only last during the program? i keep getting confused between stack and heap, by the way.

anyways, we found my first point of confusion (stack vs heap). next, i can do this.

x = malloc(3*sizeof(int));

this will make x basically be an integer array capable of holding 3 int values.

that confuses me, becasue cant i just do this instead?

int x[3];

i know theres a lot of mistakes being made in my logic, but i hope you guys can pinpoint more easily where im actually confused and what areas can be explained more in depth to me. thanks.

2 Answers

0 votes
answered Mar 18 by Peter Minarik (86,240 points)
edited Apr 1 by Peter Minarik

You can better understand stack vs heap by reading this thread (and the link from that thread as well). I really advise you to read those linked articles.

that confuses me, becasue cant i just do this instead?

So yes, (int*)malloc(3*sizeof(int)); and int x[3]; are both capable of storing 3 integers.

The difference is that the first is allocated on the heap while the latter is allocated on the stack.

So we're back to round 1: what are the stack and the heap? And when should you use one or the other?

In short, the stack should be used when speed matters, but when you want to store a lot of data you can only use the heap (as the stack has limited space). Another reason to use the heap is when your function wants to generate some data and return it to the caller. Since the stack is deallocated when your function returns, you shouldn't return any pointers to any (non-static) stack variable as that memory will be released when the function terminates. You should use the heap (with dynamic memory allocation) instead.

For instance, let's consider the following example where we have two ways to generate a sequence of random digits: GenerateRandomDigitsOnStack and GenerateRandomDigitsOnHeap.

We call both functions in the main() and print the results. You can see that the results show that in the case of GenerateRandomDigitsOnStack, the returned pointer to the array is invalid. By the grace of the compiler, in debug build, it is set to NULL to detect it easier, but if this were a proper release build, no such help would be available, instead it would be some memory garbage and we wouldn't know that we're reading some stale data.

In case of GenerateRandomDigitsOnHeap, we can safely return our allocated pointer, however, we should remember to free it (free(digits);) when we do not need it anymore to prevent memory leaks that would bloat the memory footprint of the application.

Please, also notice that the compiler warns about returning a pointer to a local stack variable.

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

void GenerateRandomDigits(uint8_t * array, size_t count)
{
    for (size_t i = 0; i < count; i++)
    {
        array[i] = rand() % 10;
        printf("%d", array[i]);
    }
    printf("\n");
}

uint8_t * GenerateRandomDigitsOnStack(size_t count)
{
    printf("GenerateRandomDigitsOnStack(count: %lu) returns: ", count);
    uint8_t digits[count];
    GenerateRandomDigits(digits, count);
    return digits;
}

uint8_t * GenerateRandomDigitsOnHeap(size_t count)
{
    printf("GenerateRandomDigitsOnHeap(count: %lu) returns: ", count);
    uint8_t * digits = (uint8_t *)malloc(sizeof(uint8_t) * count);
    GenerateRandomDigits(digits, count);
    return digits;
}

void PrintDigits(uint8_t * array, size_t size)
{
    printf("PrintDigits(%p, %lu) receives: ", array, size);
    if (array == NULL)
    {
        printf("[invalid array pointer]\n");
        return;
    }

    for (size_t i = 0; i < size; i++)
        printf("%d", array[i]);
    
    printf("\n");
}

int main()
{
    srand(time(NULL));
    
    size_t count = 10;
    uint8_t * digits = GenerateRandomDigitsOnStack(count);
    PrintDigits(digits, count);

    digits = GenerateRandomDigitsOnHeap(count);
    PrintDigits(digits, count);
    free(digits); // Only to be used with GenerateRandomDigitsOnHeap(count);

    return 0;
}

After running the code, something like this would be the output:

main.c: In function ‘GenerateRandomDigitsOnStack’:
main.c:21:12: warning: function returns address of local variable [-Wreturn-local-addr]
   21 |     return digits;
      |            ^~~~~~
GenerateRandomDigitsOnStack(count: 10) returns: 4098928275
PrintDigits((nil), 10) receives: [invalid array pointer]
GenerateRandomDigitsOnHeap(count: 10) returns: 8617229409
PrintDigits(0x55a833cf26b0, 10) receives: 8617229409

I hope this helps answer your questions.

Good luck!

0 votes
answered Mar 27 by Rybbsjjb (150 points)
Yes int x[3] can be done if we know the length of the array beforehand, but imagine if the user decides the length, n, this will not be the best way ( as far as I know...)

Problems:

1. Array are usually contiguous memory locations hence a large size will be difficult to be made available if we have a large number of other variables too that need to be allocated memory

2. As said before the memory needs to be a single continuous chunk for static allocations

Allocating the array using dynamic memory allocation functions like malloc or calloc is better suited, so you do,

pointer x = (int *) malloc( 3* sizeof(int));

The stack and heap:

See the memory, say a box, is made of both stack and heap and they start at opposite ends of box, and grow towards each other. So the memory size is actually fixed.

The thing with heap is, it is portion of memory that can be used and manipulated by the developer completely, the memory taken from the heap must be returned manually( no garbage collection, in c atleast). This can be decided on values of variable during the runtime. Hence I believe it is dynamic. Also these variables only come to existence during runtime.

But in memory in stack is handled internally, you don't get to decide the persistence and other features. ( I think I read somewhere that variables that are declared are allocated memory during the late stages of compilation or something, not 100% sure)

Hope that helped, at least partially...
Welcome to OnlineGDB Q&A, where you can ask questions related to programming and OnlineGDB IDE and and receive answers from other members of the community.
...