2

If I declare an array double x[n] where n is either a constant or an int variable, I can get it's size during runtime. But if I allocate memory using malloc this does not happen. Is this because of stack vs heap memory allocation ? If so how are array sizes for global variables determined and why can't I declare variable length arrays as global variables ? and how does deallocation work since you need to know how much memory to free ?

  • 3
    The answer to basically all of your questions is that the memory allocator privately knows how much memory it allocated, but not the type of your object. In fact, it might only know how many blocks of some fixed size it allocated, not necessarily the same as the number of bytes requested. Therefore it does not know how many _elements_ it contains, or even if it's being used as an array or something else. You are expected to keep track of usage-specific information yourself if you need it. The array `x` in your example has a known type and size at compile time, or inferable at runtime. – paddy Jul 13 '20 at 03:34
  • and also: https://stackoverflow.com/questions/2650895/if-free-knows-the-length-of-my-array-why-cant-i-ask-for-it-in-my-own-code – Antti Haapala -- Слава Україні Jul 13 '20 at 03:35
  • @paddy that would make as good an answer as any. – David C. Rankin Jul 13 '20 at 03:35
  • "Is this because of stack vs heap memory allocation ?" --> No. Location irrelevant. – chux - Reinstate Monica Jul 13 '20 at 09:52
  • "how does deallocation work since you need to know how much memory to free ?" User does not need to keep how much memory there is to free in order to call `free(ptr)`. – chux - Reinstate Monica Jul 13 '20 at 09:54

2 Answers2

4

The answer to basically all of your questions is that the memory allocator privately knows how much memory it allocated, but not the type of your object. In fact, it might only know how many blocks of some fixed size it allocated, not necessarily the same as the number of bytes requested. Therefore it does not know how many elements that "array" contains, or even if it's being used as an array at all.

You are expected to keep track of usage-specific information yourself if you need it. You simply request however many bytes you need and then use that memory however you choose. It is not the allocator's responsibility to assist you with this, which gives you full flexibility to do whatever you want.

The array x in your example has a known type and size at compile time, or can be inferred at runtime. In other words, the compiler knows that it should push some number of bytes onto the stack based on the size value and use them as an array of the defined type.

It makes less sense to have VLAs at global scope, since the whole point of the VLA is that it is allocated based on the variable size when entering a block scope. The global scope is only entered once when your program is initialized.

paddy
  • 60,864
  • 6
  • 61
  • 103
  • If I declared x as say double x[10] and make it a global variable I can still use sizeof(x). Global variables are kept in the heap, same as dynamically allocated memory right ? So does the compiler store the size of x somewhere else ? – Moshiur Rahman Jul 13 '20 at 03:51
  • 1
    No, `sizeof(x)` is constant. The value is known at compile time and hardcoded into your compiled program for any instructions that use the value or other constant derivatives of the value (_e.g._ `sizeof(x) / sizeof(*x)` is also constant and is computed at compile time) – paddy Jul 13 '20 at 04:01
  • Then how does sizeof(x) determine it's value for variable length arrays ? – Moshiur Rahman Jul 13 '20 at 04:07
  • 1
    @moshiur: The compiler invents a local variable which holds that value. Note that the size of `x` is only known in the scope in which `x` is declared. If you pass `x` as an argument to another function, that other function does not know its size. – rici Jul 13 '20 at 04:16
  • @MoshiurRahman: Where did you get the idea that globals are stored on the heap? – John Bode Jul 13 '20 at 04:25
  • @rici I created a program with something like this : int n; scanf("%i", &n); x[n]; printf("%lu\n", sizeof(x)); and it worked. Your answer explains this well. Thanks. – Moshiur Rahman Jul 13 '20 at 05:21
  • @JohnBode Oh, it's stored in the data segment. I wasn't sure. – Moshiur Rahman Jul 13 '20 at 05:21
  • 2
    It doesn't matter where it's stored. The operating system could choose to keep the data segment in a heap if it wants to. This is not your concern unless you're developing OS kernels. – paddy Jul 13 '20 at 05:23
0

During translation, the compiler keeps track of all variable definitions and their sizes. Except for VLAs, the sizeof operator is evaluated at compile time, not runtime. How the sizes of VLAs are tracked is up to the individual implementation.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • I think what @rici said in the comments is right. Otherwise how would int n; scanf("%i", &n); x[n]; printf("%lu\n", sizeof(x)); work ? So, sizeof can be evaluated at runtime and according to ricci's comment the compiler creates a new variable to track it. Maybe at compile time sizeof is replaced by something like n*sizeof(double) = n*8 ??? – Moshiur Rahman Jul 13 '20 at 05:24
  • @MoshiurRahman: rici’s right that there must be some kind metadata associated with the VLA, but how that’s accomplished is up to each individual implementation. – John Bode Jul 13 '20 at 12:58