-2

I was wondering if someone could explain the differences between the memory allocation for ai and *pai

int ai[10];
int *pai = (int * ) calloc (10, sizeof(int));

I understand the second one is dynamically allocated but im struggling to explain why.

bolov
  • 72,283
  • 15
  • 145
  • 224
freya
  • 41
  • 1
  • 3
  • 7
    Why? Because that's what `calloc()` and related functions *do*. Dynamic allocation means that you call a function at runtime to allocate memory. – John Bollinger Jan 08 '18 at 15:01
  • The `*` is not part of the variable name, it is part of its *type*. `pai` is allocated in exactly the same way as `ai`, but `*pai` (the thing that `pai` is pointing at) is probably stored on the process heap, because `calloc()` is used to give the value, which is a pointer. The pointer itself is stored in the same way as `ai`. – cdarke Jan 08 '18 at 15:01
  • Do you need to explain this in terms of where memory is allocated? Or in terms of when allocation happens? Or in terms of how the memory is used? – Yunnosch Jan 08 '18 at 15:02
  • 1
    The differences are that `ai` is in the data block (I believe) whereas `*pai` is on the heap, as mentioned. Also, `pai` can be given another value but `ai` is fixed. – Tomas By Jan 08 '18 at 15:04
  • @cdarke Therefore it is completely fine to ask for the object `*pai` (even it is not an identifier, but an expression that results in an object) and not the object `pai`, what would be a stupid Q. – Amin Negm-Awad Jan 08 '18 at 15:07
  • 1
    @AminNegm-Awad: yes it is, I just wanted to make sure that the OP understood the difference. – cdarke Jan 08 '18 at 19:09

5 Answers5

3

Let's see what is being specified in standard (difference wise)

From 7.22.3.1 (Under Memory management functions)

... The lifetime of an allocated object extends from the allocation until the deallocation.

So yes, this is for dynamically allocated memory. Their lifetime is different from that of local variables. By calling free they are deallocated. Until then they will be alive. Doesn't depend on the life time of the scope on which they are created.

The first one is having automatic storage duration. This is the primary difference. So in the functions scope where it is declared, when it ends then it's lifetime will be over.

Also some people say that there is a heap and stack - but (un)fortunately C standard doesn't mention it. It is completely implementation of the features expected by the C standard. The implementation can be anything. The differences presented is least bothered about those kind of stuff.

As a conceptual redpill (taken from movie Matrix) pai is of automatic storage duration but the address of the memory it contains is not. The variable pai will be lost when the function where it is defined is executed. But the memory it points to, doesn't.

Well why is it called dynamic allocation?

Know one thing - when in programming we say dynamic in the context of language - it means we are doing something in runtime. Same here, we are allocating some memory when in run time by calling functions like malloc,calloc etc. That's why dynamic allocation.

user2736738
  • 30,591
  • 5
  • 42
  • 56
  • *"So in the function where it is defined, when it ends.."* - Isn't it supposed to be in the **scope** instead of the function? – SHG Jan 08 '18 at 15:21
  • @SHG.: Yes you are right. Edited. – user2736738 Jan 08 '18 at 15:22
  • okay, when can the memory used by ai and pai to be available for reuse ? – freya Jan 08 '18 at 15:26
  • @freya.: `ai` will be available for reuse when the scope on which it exists end but for dynamic memory allocation it will be reusable as long as you free it - it will be then a candidate for next allocation call. – user2736738 Jan 08 '18 at 15:28
0

The array ai is allocated on the stack, it implicitly goes out of scope, when the end of the function is reached. The pointer pai points to a memory location, which can be an array or a single element of the type pointed to, the memory is allocated on the heap and must be freed later. The second can be passed back to the function-caller on the end of the function and can even be resized with realloc (realloc does not clear the new memory like calloc does, malloc is like calloc without zeroing out the new memory). The first is for fast array computation and should be in the cache most of the time. The second is for unknown lenght of arrays, when the function is called. When the size is known, many programmers tend to define an array in the caller and pass it to the function, which modifies it. The array is implicitly converted to a pointer when calling the function.

Some library implementations store a pointer to an array in the global section, which can be reallocated. Or they have a fixed length array in global space. These variables are recommended to be thread_local. The user does not have to care about the memorymanagement of the variable of the other library.

library.h

const char* getResourceString(int id);

library.c

thread_local char* string_buf = NULL;

const char* getResourceString(int id) {
    int i = getResourceSize(id);

    string_buf = realloc(string_buf, i);

    // fill the memory

    return string_buffer;
};
cmdLP
  • 1,658
  • 9
  • 19
0

Gerenally speaking, automatically allocated objects will be on the stack, while dynamically allocated objects will be on the heap. Although this distinction is implementation (not standard) dependent, stack and heap are the most commonly used way to manage memory in C programs. They are basically two distinct regions of memory, the first is dedicated to automatic allocations and the second is dedicated to dynamic allocations. So when you call a function (say, the main function) all the objects declared in the scope of this function will be stacked (automatically allocated in the stack). If some dynamic allocation happens in this function, the memory will be allocated in the heap so that all pointers to this area will be pointing to objects outside the stack. When your function returns, all objects in the stack are also automatically unstacked and virtually don't exist anymore. But all objects in the heap will exist until you deallocate them (or they will be forcefully deallocated by the OS when the program ends). Arrays are structures that can be allocated automatically or dynamically. See this example:

int * automaticFactor() //wrong, see below
{
    int x[10];
    return &x[0];
}

int * dynamicFactor()
{
    int * y = (int *) malloc(sizeof(int) * 10);
    return &y[0];
}

int main()
{
    //this will not work because &x[0] points to the stack
    //and that area will be unstacked after the function return
    int * n = automaticFactor();

    //this will work because &y[0] points to the heap
    //and that area will be in the heap until manual deallocation
    int * m = dynamicFactor();

    return 0;
}

Note that the pointers themselves are in the stack. What is in the heap is the area they are pointing to. So when you declare a pointer inside a function (such as the y of the example), it will also be unstacked at the end of the function. But since its value (i.e. the address of the allocated area) was returned to a pointer outside the function (i.e. to m), you will not lose track of the area allocated in the heap by the function.

Jango
  • 378
  • 4
  • 8
0

In the first line, you create a variable of an array type, but the symbol ai is a constant pointer to this variable.

in the second line, you create a pointer type variable. then you allocate an array dynamically with calloc() and you puts it's address in the pointer.

Camion
  • 1,264
  • 9
  • 22
  • The identifier associated with an array object designates *the array*, not a pointer. In most contexts, evaluation of that identifier will result in a *conversion* to a pointer (to the first array element), but that's observably different from the identifier representing a pointer in the first place. In particular, you can tell the difference via the `sizeof` operator. – John Bollinger Jan 08 '18 at 15:46
0

These are quite different operations:

int ai[10];

declares an array object of 10 ints. If it is declared inside a block, it will have automatic storage duration, meaning that it will vanish at block end (both identifier and data). If it is declared outside any block (at file level) it will have static storage duration and will exist throughout all program.

int *pai = calloc (10, sizeof(int));  // DON'T CAST MALLOC IN C

declares a pointer to an allocated zone of memory that can contains ten integers. You can use pai as a pointer to the first element of an array and do pointer arithmetics on it. But sizeof(pai) is sizeof(int *). The array will have dynamic storage duration meaning that its life will end:

  • if the allocated block of memory is freed
  • if it is reused to store other objects

    double * pd = pai;
    for (int i=1; i<5; i++) {      // assuming sizeof(double) == 2 * sizeof(int) here
        pd[i] = i;                 // the allocated memory now contains 5 double
    }
    

So in both case you can use the identifier as pointing to an array of 10 integers, but first one is an integer array object while second one is just a pointer to a block of dynamic memory (memory with no declared type that can take the type of an object that will be copied/created there) .

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252