Подтвердить что ты не робот

Переменные стека против переменных кучи

Я правильно понимаю, что:

char *buff[500];

... создает переменную стека и:

char *buff = (char *)malloc(500);

... создает переменную кучи?

Если это правильно, когда и почему вы используете переменные кучи над переменными стека и наоборот. Я понимаю, что стек быстрее, есть что-то еще.

Последний вопрос, является ли основная функция стек стека в стеке?

4b9b3361

Ответ 1

Да, сначала создается массив указателей char в стеке, около 500*4 bytes, а второй выделяет 500 символов в куче и указывает на стек char ptr.

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

Если вы выделяете слишком много в стеке, вы можете закончиться из стека и умереть, main, поскольку все выполняемые вами функции имеют стек стека в стеке, и все локальные переменные функции хранятся там, поэтому слишком глубокий вызов функции также может привести вас к потоку stackoverflow.

В общем, хорошим правилом является выделение всего, что вы часто используете, и более ста байтов в куче, а также небольшие переменные и указатели в стеке.

Ответ 2

Увидев, что вы написали

char *buff = (char *)malloc(500);

вы, вероятно, имели в виду

char buff[500];    instead of 
char* buff[500];

в вашем первом примере (так что у вас есть char -array, а не массив указателей на символы)

Да, "распределение" в стеке происходит быстрее, потому что вы просто увеличиваете указатель, хранящийся в регистре ESP.

Вы нуждаетесь кучи-переменные, если хотите:

1) больше памяти, чем подходит в стеке (обычно намного раньше)

2) передать память, выделенную вызываемой функцией вызывающей функции.

Ответ 3

Ваш buff не эквивалентен.

Первый (char *buff[500]) - массив из 500 указателей; второй (char *buff = (char *)malloc(500)) является указателем.

Указатель (в стеке) указывает на 500 байт памяти (если вызов malloc преуспел) в куче.
Массив указателей находится в стеке. Его указатели не инициализируются.

Ответ 4

Если не использовать C99, используя стек, размер вашего массива должен быть известен во время компиляции. Это означает, что вы не можете сделать:

int size = 3; // somewhere, possibly from user input
char *buff[size];

Но используя "кучу" (динамическое распределение), вы можете предоставить любые размеры, которые вам нравятся. Это потому, что выделение памяти выполняется во время выполнения, а не жестко закодировано в исполняемый файл.

Ответ 5

Переменные кучи могут создаваться динамически, т.е. вы можете задать размер для своего пользователя и malloc - новую переменную с таким размером.

Размер переменной стека должен быть известен во время компиляции.

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

Ответ 6

Это действительно переменная, выделенная в стеке:

char buff[500]; // You had a typo here?

и это находится в куче:

char *buff = (char *)malloc(500);

Почему вы используете один и тот же?

  • В char *buff[500] значение 500 должно быть константой времени компиляции. Вы не можете использовать его, если 500 вычисляется во время выполнения.
  • С другой стороны, распределения стека являются мгновенными, в то время как распределения кучи требуют времени (таким образом, они несут затраты времени исполнения).
  • Пространство в стеке ограничено размером стека потока (обычно 1 МБ до того, как вы получите переполнение стека), в то время как в куче гораздо больше доступно.
  • Если вы выделяете массив в стеке достаточно большим, чтобы заняться более чем двумя страницами виртуальной памяти, управляемыми ОС, и получить доступ к концу массива, прежде чем делать что-либо еще, есть возможность получить ошибку защиты ( это зависит от ОС)

Наконец: каждая вызванная функция имеет фрейм в стеке. Функция main не отличается. Это даже не является более особенным, чем другие функции в вашей программе, поскольку, когда ваша программа запускает первый код, который выполняется, находится внутри the C runtime environment. После того, как среда выполнения готова начать выполнение собственного кода, она вызывает main так же, как вы вызывали бы любую другую функцию.

Ответ 7

Эти два не эквивалентны. Первый - это массив размером 500 (в стеке) с указателями на символы. Второй - указатель на кусок памяти 500, который можно использовать с оператором индексирования.

char buff[500];

char *buff = (char *)malloc(sizeof(char)*500);

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

Ответ 8

В стандарте C нет ни кучи слов, ни стека. Здесь у нас есть две длительности хранения (всего 4): автоматическая и выделенная:

  • char buff[500]; // note the missing * to match the malloc example
    

    внутри функции объявляет объект buff как массив char и время автоматического хранения. Объект перестанет быть, когда будет заблокирован блок, где был объявлен объект.

  • char *buff = malloc(500);  // no cast necessary; this is C
    

    объявит buff как указатель на char. malloc зарезервирует 500 непрерывных байтов и вернет указатель на него. Возвращаемый 500-байтовый объект будет существовать до тех пор, пока он явно не будет free d с вызовом free. Говорят, что объект имеет выделенную продолжительность хранения.


Об этом говорит весь стандарт C. Он не указывает, что char buff[500] необходимо выделить из "стека" или что должен быть стек. Он не указывает, что malloc нужно использовать некоторую "кучу". Напротив, компилятор может внутренне реализовать char buff[500] как

{
    char *buff = malloc(500);
    free(buff);
}

Или он может вывести, что выделенная память не используется или что она используется только один раз и использует распределение на основе стека вместо фактического вызова malloc.

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