Ответ 1
С помощью VLA оператор sizeof
не является константой времени компиляции. Он оценивается во время выполнения. В вашем вопросе тип &arr
есть int (*)[n];
- указатель на массив значений n
типа int
, где n
- значение времени выполнения. Следовательно, как вы заметили, &arr + 1
(круглые скобки не нужны, кроме круглых скобок, отметив, что скобки не нужны) - это начало массива после arr
- адрес sizeof(arr)
байтов превышает значение arr
.
Вы можете напечатать размер arr
; он даст вам соответствующий размер (printf()
модификатор z
). Вы можете распечатать разницу между &arr + 1
и arr
, и вы получите размер как ptrdiff_t
(printf()
модификатор t
).
Следовательно:
#include <stdio.h>
int main(void)
{
int n;
if (scanf("%d", &n) == 1)
{
int arr[n];
void* ptr = (&arr) + 1;
printf("%p\n", arr);
printf("%p\n", ptr);
printf("Size: %zu\n", sizeof(arr));
printf("Diff: %td\n", ptr - (void *)arr);
}
return 0;
}
И два прогона прогона (название программы vla59
):
$ vla59
23
0x7ffee8106410
0x7ffee810646c
Size: 92
Diff: 92
$ vla59
16
0x7ffeeace7420
0x7ffeeace7460
Size: 64
Diff: 64
$
Нет повторной компиляции, но sizeof()
является правильным при каждом запуске программы. Он рассчитывается во время выполнения.
В самом деле, вы можете даже использовать цикл с разным размером каждый раз:
#include <stdio.h>
int main(void)
{
int n;
while (printf("Size: ") > 0 && scanf("%d", &n) == 1 && n > 0)
{
int arr[n];
void* ptr = (&arr) + 1;
printf("Base: %p\n", arr);
printf("Next: %p\n", ptr);
printf("Size: %zu\n", sizeof(arr));
printf("Diff: %td\n", ptr - (void *)arr);
}
return 0;
}
Пример прогона vla11
:
$ vla11
Size: 23
Base: 0x7ffee3e55410
Next: 0x7ffee3e5546c
Size: 92
Diff: 92
Size: 16
Base: 0x7ffee3e55420
Next: 0x7ffee3e55460
Size: 64
Diff: 64
Size: 2234
Base: 0x7ffee3e53180
Next: 0x7ffee3e55468
Size: 8936
Diff: 8936
Size: -1
$