6

I know defining an array in C is not possible with variable length, but what about just declaring it?

#include <stdio.h>

int main ()
{
  int num = 5;
  int array[num];
  printf("%d\n",sizeof(array));
  return 0;
}

Above code compiles and prints 20. Is it undefined behaviour?

Edit 1:

If I write

  int array[num] = {0};

I will get error: variable-sized object may not be initialized.

Edit 2:

#include <stdio.h>

void change(int *in){
  *in = 6;
}

int main ()
{
  int num = 5;
  change(&num);
  int array[num];
  printf("%d\n",sizeof(array));
  return 0;
}

gcc test.c.

Above prints 24 which is correct. How does the compiler know the correct size during compile time?

Community
  • 1
  • 1
  • Does this answer your question? [How do I determine the size of my array in C?](https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c) – Adrian Mole Apr 21 '20 at 16:03
  • 2
    The `sizeof` operator returns the size in *bytes*. – Some programmer dude Apr 21 '20 at 16:03
  • Thanks, but how is this working tho? how is the compiler allocating the number of bytes correctly? –  Apr 21 '20 at 16:04
  • I believe you're wrong on two accounts: 1) an array with variable length in C IS possible, and 2) if what you've done compiles, it's not C. It's C++. I take that back. This shouldn't compile in C++ either. Maybe it's just throwing warnings though that I'm used to making into errros with -Wall -Werror. What's your compilation command? – Gabriel Staples Apr 21 '20 at 16:04
  • 2
    Defining a variable length array in C99 and later is possible, although it's an optional feature in C11. – Paul Hankin Apr 21 '20 at 16:04
  • I have added another example above. –  Apr 21 '20 at 16:06
  • Yes, it's undefined behavior, because %d is not the correct printf directive to print a value of type `sizeof_t`. – Paul Hankin Apr 21 '20 at 16:06
  • The error message doesn't say you cannot declare a variable length array, only that you cannot use an array initializer with a VLA – UnholySheep Apr 21 '20 at 16:07
  • If the compiler can allocate bytes correctly with only declaration, why can't it initialize it them same way too? –  Apr 21 '20 at 16:09
  • 2
    Please post your compile command. – Gabriel Staples Apr 21 '20 at 16:10
  • I added Edit 2. –  Apr 21 '20 at 16:12

1 Answers1

7

The code is clean C99 code. C99 added support for VLAs (variable length arrays). C11 made the support optional. Your code compiles cleanly, except that the printf() should use %zu rather than %d to print the value from sizeof().

C11 §6.5.3.4 The sizeof and _Alignof operators says:

¶2 The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

In your code, the size is evaluated at run-time. You could have code such as:

printf("Enter the array size: ");
if (scanf("%d", &n) != 1 || n <= 0 || n > 1024)
{
    fprintf(stderr, "Did not get a valid size\n");
    exit(EXIT_FAILURE);
}

int array[n];

and then printing the size will still be correct — the size is calculated (evaluated) at run-time. But that's only for VLAs.

VLAs may not be initialized — the standard is clear about that, too — §6.7.9 Initialization says:

¶3 The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a variable length array type.

You cannot write an initializer for a VLA. That's a 'constraint'; it is mandatory that the compiler complains about the abuse of the standard.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • How does the compiler know the correct size during compile time to allocate the array? Why can't it do the same when I'm initializing the array? I have added `Edit 2` –  Apr 21 '20 at 16:14
  • Good thing you also clarified that the value of the size variable could well be unknown at compile time (i.e. user input or non trivial expression). In your code snippet you are reading `n` twice though (cannot edit for some reason). Also for the purposes of this example, I think the code could be simpler – kyriakosSt Apr 21 '20 at 16:15
  • 2
    It doesn't know the correct size at compile time. For a VLA, it determines the correct size at run-time. – Jonathan Leffler Apr 21 '20 at 16:15
  • @kyriakosSt — oops; removed the superfluous `scanf()`. Thanks! (Maybe you couldn't edit because I was editing too.) – Jonathan Leffler Apr 21 '20 at 16:16
  • But I still don't get why can't it do the same with `int array[num] = {0};`, whatever it's doing. Why is this a problem? and `int array[num];` isn't? –  Apr 21 '20 at 16:16
  • @JonathanLeffler one of the masters is here. +1 – Soner from The Ottoman Empire Apr 21 '20 at 16:17
  • 2
    The C standard says "thou shalt not". And while it probably could initialize all elements of the array with zero as you'd like, that isn't the way the standard works. There is a certain logic to the standard — it isn't as flexible as you'd like. I'd like it to handle ranges of designated initializers for array initialization: `int array[30] = { [12:24] = 39 };` meaning 0..11 and 25..29 are zeroed. It doesn't do that — GCC has an extension using `...` to separate the ranges, which has its own set of problems. – Jonathan Leffler Apr 21 '20 at 16:18
  • so in this case, array is allocated during run time correct? and for some reason it doesn't/can't initialize it at the same time? –  Apr 21 '20 at 16:19
  • @Alex you should abide by the standards if you don't want to incur -- > [Ariane 5](https://itsfoss.com/a-floating-point-error-that-caused-a-damage-worth-half-a-billion). By the way, I learned it from Jonathan Leffler as well some years ago. – Soner from The Ottoman Empire Apr 21 '20 at 16:19
  • Thank you, so just wanted to confirm this again: array is allocated during run time correct? and for some reason it doesn't/can't initialize it at the same time? –  Apr 21 '20 at 16:23
  • 2
    @Alex — yes, the array is allocated during run-time, and its size is determined at run-time (even in your code — and even if you'd used `const int n = 5;` because that's a constant integer, not an integer constant). And there is a blanket prohibition on initialization for a VLA in §6.7.9¶3 that says "thou shalt not provide an initializer for a VLA". – Jonathan Leffler Apr 21 '20 at 16:23
  • Oh I thought using `const` makes them like `integer constants`! Is there an article that says their difference? –  Apr 21 '20 at 16:25
  • 1
    @Alex: In C++, yes (`const` does make them into an integer constant as well as a constant integer). But this is C and the rules are different — they are different languages. C++ doesn't officially have VLA support — though GCC (the GNU Compiler Collection) does provide support for them via `g++` as an extension, with no initialization, of course. – Jonathan Leffler Apr 21 '20 at 16:26