Почему можно объявить массив в C без определения его длины? - PullRequest
6 голосов
/ 11 марта 2019

В C вы должны определить длину массива. Тем не менее, следующий фрагмент кода действителен:

int arr[] = {10, 20, 30, 40, 50};

Почему этот приемлемый синтаксис?

Ответы [ 3 ]

14 голосов
/ 11 марта 2019

Это удобная функция. Размер массива определяется из инициализатора, поэтому вам не нужно его записывать:

int arr[] = {10, 20, 30, 40, 50};

эквивалентно

int arr[5] = {10, 20, 30, 40, 50};

Другим примером этого (спасибо Евгению Ш.) являются инициализаторы строк:

char str[] = "asd";

эквивалентно

char str[4] = "asd";

Важно знать, что при использовании в качестве типа для параметра функции все иначе. Все следующие формы:

void foo(int v[])

void foo(int v[1])
void foo(int v[5])
void foo(int v[1000])

Все эквивалентны между собой, и они превращаются в это:

void foo(int* v)

Всегда используйте последний (void foo(int* v)), а не другие. Потому что первые формы создают видимость массива, но в действительности у вас есть указатель. Это вводит в заблуждение.

6 голосов
/ 11 марта 2019

В дополнение к существующему ответу, цитата из C11, глава §6.7.9, P22

Если инициализируется массив неизвестного размера, его размер определяется по наибольшему индексируемому элементус явным инициализатором.Тип массива завершается в конце его списка инициализатора.

Таким образом, размер массива будет определяться «наибольшим индексированным элементом» или, проще говоря, количеством присутствующих элементов.в списке инициализаторов.

2 голосов
/ 14 марта 2019

Это приемлемо, потому что размер (в байтах) целого числа известен во время компиляции, и, таким образом, компилятор знает, сколько места требуется для всего этого списка.

Но чтобы понять этот ответ, нужно немного покопаться и спросить, почему так важно знать точный размер во время компиляции. Вообще говоря: Чтобы определить виртуальное адресное пространство для вашей программы. Частью этого является стек, в котором хранятся локальные переменные и который не следует путать с кучей памяти (где работает malloc). Стек представляет собой список LIFO, а также содержит все вызовы функций вместе со своими параметрами. Он используется в конце функции для возврата назад, откуда вы пришли, и для этого хранится адрес памяти. Все, что вы кладете в стек, пока вы выполняете свою функцию, должно быть освобождено, чтобы получить правильный обратный адрес и избежать потенциального сбоя.

К счастью, C делает этот тип управления памятью автоматически для нас и освобождает все наши автоматические переменные , когда они считаются «вне области». Для этого нам нужен точный размер того, что мы поместили в стек, и поэтому компилятору уже нужно знать этот размер.

Чтобы проиллюстрировать, как компилятор переводит ваш код и жестко кодирует эти числа, см. Здесь:

$ echo "int int_size = sizeof(int); int main(void) { int arr[] = {10, 20, 30, 40, 50}; }" |\ 
    gcc -c -xc -S -o- -masm=intel - 


    .file   ""
    .intel_syntax noprefix
    .text
    .globl  main
    .type   main, @function
# [...] removed int_size here to keep it shorter. its "4" ;)
main:
.LFB0:
    .cfi_startproc
    push    rbp               # < backup rbp / stack base pointer
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov rbp, rsp              # < rsp / stack shift pointer = top of the stack
    .cfi_def_cfa_register 6
    sub rsp, 32
    mov rax, QWORD PTR fs:40
    mov QWORD PTR -8[rbp], rax
    xor eax, eax
    mov DWORD PTR -32[rbp], 10  # < 10 is one element from the array
    mov DWORD PTR -28[rbp], 20  # < -28 means relative to the top of the stack
    mov DWORD PTR -24[rbp], 30 
    mov DWORD PTR -20[rbp], 40
    mov DWORD PTR -16[rbp], 50
    mov eax, 0
    mov rdx, QWORD PTR -8[rbp]
    xor rdx, QWORD PTR fs:40
    je  .L3
    call    __stack_chk_fail@PLT
.L3:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (GNU) 8.2.1 20181127"
    .section    .note.GNU-stack,"",@progbits
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...