Как компилятор выделить память, не зная размер во время компиляции?

Я написал программу на C, которая принимает целочисленные входные данные от пользователя, который используется в качестве размера массива целых чисел, и используя это значение, он объявляет массив заданного размера, и я подтверждаю это проверка размера массива.

Код:

#include <stdio.h>
int main(int argc, char const *argv[])
{
    int n;
    scanf("%d",&n);
    int k[n];
    printf("%ld",sizeof(k));
    return 0;
}

и на удивление это правильно! Программа способна создать массив нужного размера. Но все статическое выделение памяти выполняется во время компиляции, а во время компиляции значение " N " не известно, так как компилятор может выделить память нужного размера?

Если мы можем выделить необходимый объем памяти просто так, то какая польза от динамической распределения с помощью функции malloc()иметода calloc()`?

Комментарии к вопросу (11)
Решение

Это не "от статического распределения память". Массив к - это переменная, массив длина (вла), что означает, что память для этого массива выделяется во время выполнения. Размер будет определен во время выполнения значение "N".

Спецификация языка не диктует какого-либо конкретного механизма распределения, но в типичной реализации своего "К", как правило, в конечном итоге просто как int * указатель с фактическими блок памяти выделяется на стеке во время выполнения.

Для оператора вла размер оценивается во время выполнения, а также, который является, почему вы получаете правильное значение из него в свой эксперимент. Просто используйте %ЦУ "(а не " %ЛД) для распечатки значений типа size_t``.

Основная цель функция malloc (и другие функции динамического распределения памяти), чтобы переопределить рамки правил жизни, которые применимы к локальным объектам. Т. е. память, выделенная с функция malloc остатки, выделенных на "вечно и", или пока вы не освободить его "свободный". Память, выделенная с функция malloc не автоматически освобождается в конце блока.

Вла, как в вашем примере, не дает это и"Сфера-победы над" и функциональности. Массив " к " до сих пор подчиняется обычной рамки-правила жизни: ее срок службы заканчивается в конце блока. По этой причине, в общем случае, вла не может заменить функция malloc и другие функции динамического выделения памяти.

Но в конкретных случаях, когда вы не'т нужна, чтобы "поражение рамки" и просто пользоваться функция malloc, чтобы выделить время выполнения размера массива, вла действительно может рассматриваться в качестве замены для функция malloc. Только имейте в виду, опять же, что Влас обычно выделяется в стеке и выделении больших кусков памяти в стеке и по сей день остается довольно сомнительной практики программирования.

Комментарии (17)

В C, средства, с помощью которых компилятор поддерживает Влас (переменной длины массива), компилятор - это не'т придется использовать функции malloc(), и может (и часто делает) использовать то, что иногда называется "стек" Память - например, через систему конкретных функций, таких какфункция alloca ()`, которые не являются частью стандарта C. Если она использует стек, максимальный размер массива, как правило, значительно меньше, чем это возможно с помощью функции malloc (), потому что современные операционные системы позволяют программы гораздо меньшие квоты памяти стека.

Комментарии (1)

Память для массивов переменной длины, очевидно, может'т быть статически. Однако она может быть выделена на стеке. Как правило, это предполагает использование и"указатель рама и" отслеживать местоположение функции стековый фрейм в условиях динамично определены изменения указателя стека.

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

#include 
int main(int argc, char const *argv[])
{
    int n;
    scanf("%d",&n);
    int k[n];
    printf("%s %ld",k,sizeof(k));
    return 0;
}

Godbolt при компиляции для ARM с помощью GCC 6.3 (с помощью рукоятки, потому что я могу прочитать руку АСМ) компилирует это https://godbolt.org/g/5ZnHfa. (мои комментарии)

main:
        push    {fp, lr}      ; Save fp and lr on the stack
        add     fp, sp, #4    ; Create a "frame pointer" so we know where
                              ; our stack frame is even after applying a 
                              ; dynamic offset to the stack pointer.
        sub     sp, sp, #8    ; allocate 8 bytes on the stack (8 rather
                              ; than 4 due to ABI alignment
                              ; requirements)
        sub     r1, fp, #8    ; load r1 with a pointer to n
        ldr     r0, .L3       ; load pointer to format string for scanf
                              ; into r0
        bl      scanf         ; call scanf (arguments in r0 and r1)
        ldr     r2, [fp, #-8] ; load r2 with value of n
        ldr     r0, .L3+4     ; load pointer to format string for printf
                              ; into r0
        lsl     r2, r2, #2    ; multiply n by 4
        add     r3, r2, #10   ; add 10 to n*4 (not sure why it used 10,
                              ; 7 would seem sufficient)
        bic     r3, r3, #7    ; and clear the low bits so it is a
                              ; multiple of 8 (stack alignment again) 
        sub     sp, sp, r3    ; actually allocate the dynamic array on
                              ; the stack
        mov     r1, sp        ; store a pointer to the dynamic size array
                              ; in r1
        bl      printf        ; call printf (arguments in r0, r1 and r2)
        mov     r0, #0        ; set r0 to 0
        sub     sp, fp, #4    ; use the frame pointer to restore the
                              ; stack pointer
        pop     {fp, lr}      ; restore fp and lr
        bx      lr            ; return to the caller (return value in r0)
.L3:
        .word   .LC0
        .word   .LC1
.LC0:
        .ascii  "%d\000"
.LC1:
        .ascii  "%s %ld\000"
Комментарии (0)

Память для этой конструкции, которая называется "переменную длину массива и", вла, выделяется на стеке, по аналогии с распределения. Как именно это происходит, зависит именно от того, какой компилятор вы'повторно используя, но сути это's в случае расчета размера когда известно, а затем вычитания [1] общая площадь от стека-указки.

Вам нужна функция malloc и друзей, потому что это распределение на "умирает" Когда вы покинете функцию. [И это's не действует в стандарт C++]

[1] для типичных процессоров, использующих стек, что "перерастает& "на ноль".

Комментарии (11)

Когда он сказал, что компилятор выделяет память для переменных в компиляции, это означает, что размещение этих переменных принимается и внедряется в исполняемый код, который компилятор генерирует, а не то, что компилятор делает для них доступными в то время как он работает. Фактическое динамическое выделение памяти осуществляется автоматически программой, когда она работает.

Комментарии (0)