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?

11
  • Does this answer your question? How do I determine the size of my array in C? Commented Apr 21, 2020 at 16:03
  • 2
    The sizeof operator returns the size in bytes. Commented Apr 21, 2020 at 16:03
  • Thanks, but how is this working tho? how is the compiler allocating the number of bytes correctly? Commented Apr 21, 2020 at 16:04
  • 2
    Defining a variable length array in C99 and later is possible, although it's an optional feature in C11. Commented Apr 21, 2020 at 16:04
  • 2
    Please post your compile command. Commented Apr 21, 2020 at 16:10

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

13 Comments

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
It doesn't know the correct size at compile time. For a VLA, it determines the correct size at run-time.
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.
@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".
@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.
|