3

According to GNU's documentation on Arrays of Variable Length, one can use the sizeof operator for determining the size of a variable length array that was passed into a function:

You can also use variable-length arrays as arguments to functions:

struct entry
tester (int len, char data[len][len])
{
  /* … */
}

The length of an array is computed once when the storage is allocated and is remembered for the scope of the array in case you access it with sizeof.

However, when trying this example with the complete code example below, the sizeof operator returns the size of the pointer, not the size of the allocated vla, as is expected based on the GNU snippet above.

I understand that passing arrays in C is akin to passing a pointer to the first element of the array, but since we're specifying the size in this case in the function signature, I would expect the behavior to mimic when using sizeof in the scope of where the array is declared.

I also realize I could use the len argument to figure out the size; but as a matter of convenience and understanding the GNU implementation I still think this is an interesting (if not important) question.

Thank you in advance to anyone who can provide insight into this!

// file: vla.c
#include <stdio.h>

void foo(int len, char data[len][len]) {
  printf("sizeof \"foo\" data: %lu\n", sizeof(data));
}

int main(int argc, char * argv[]) {
  char data[argc][argc];
  printf("sizeof \"main\" data: %lu\n", sizeof(data));
  foo(argc, data);
}

Compiled using:

gcc vla.c -o vla -std=c11

Called using:

./vla 2 3 4 5

Output:

sizeof "main" data: 25
sizeof "foo" data: 8

Analysis:

The size of the main data makes sense; argc is 5, therefore it's a (5 * 5 = 25) byte 2D array.

The size of the foo data was expected to also be 25, but is instead the size of the pointer. Seemingly the compiler is not using the fact that it knows the size of data within foo since it's part of the function signature.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
dtracy
  • 33
  • 5
  • 2
    I suspect you'll find that the normal rules apply to function arguments (you get the size of a pointer). What the text you quote is mainly referring to is arrays defined inside a function (you can't define variable size arrays at global scope). Having said that, the manual reference definitely implies that what you're doing should work. – Jonathan Leffler Aug 03 '18 at 04:53
  • 2
    Aside: Better to use `"%zu"` with `size_t` --> `printf("%zu\n", sizeof(...));` – chux - Reinstate Monica Aug 03 '18 at 04:57
  • After some frenzied cogitation, I think that storage isn't allocated when you call a function. I think the paragraph after the sample code is a non sequitur. But it isn't obvious from what the manual says. – Jonathan Leffler Aug 03 '18 at 05:03
  • @JonathanLeffler, I agree with that assessment. Also thanks for the formatting fixes, much appreciated! – dtracy Aug 03 '18 at 05:15

1 Answers1

5

An argument declared char data[len][len] is really char (*data)[len], a pointer to a VLA. There is no such thing as an actual array argument, and the first len in the declaration is meaningless. If you use sizeof *data, you will get back len though, since the pointed-to type is variably modified.

If you want both lens to be meaningful, you can pass a pointer-to-whole-array type rather than a pointer-to-first-element, declaring the argument char (*data)[len][len]. Now sizeof *data is len*len. But you'll need to use (*data)[i][j] to access it. You'll also need to use the & operator when calling the function:

int l = 42;
char array[l][l];
foo(l, &array);
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    It should be noted [the page OP refers to](https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html) is poorly written. It says “You can also use variable-lenth arrays as arguments to functions” and gives the example of an argument declared `char data[len][len]`. This might be technically correct, as an array can be “used” as an argument for this function, but it is nonetheless converted to a pointer, and the wording is misleading, perhaps suggesting GCC is supporting some C expansion or deviation… – Eric Postpischil Aug 03 '18 at 11:35
  • … The type `char data[len][len]` is likely intended to make the point that the second dimension is variable-length. The wording should likely have said that variable-length arrays may be used as parts of types passed to functions, using an example such as `char (*data)[len]`. – Eric Postpischil Aug 03 '18 at 11:36