it-roy-ru.com

Разница между типом массива и массивом, выделенным с помощью malloc

Сегодня я помогал своему другу с кодом C и обнаружил странное поведение, которое не мог объяснить ему, почему это происходит. У нас был файл TSV со списком целых чисел, с int каждой строкой. Первая строка - это количество строк в списке.

У нас также был файл c с очень простым «readfile». Первая строка была прочитана, количество строк, затем произошла инициализация:

int list[n]

и, наконец, цикл для n с помощью fscanf.

Для маленьких n (до ~ 100.000) все было хорошо. Тем не менее, мы обнаружили, что, когда n было большим (10 ^ 6), произошла ошибка.

Наконец, мы изменили инициализацию списка на

int *list = malloc(n*sizeof(int))

и все, когда хорошо, даже с очень большим п.

Может кто-нибудь объяснить, почему это произошло? что стало причиной ошибки seg с int list [n], которая была остановлена, когда мы начали использовать list = malloc (n * sizeof (int))?

58
Jorge Leitão

Здесь есть несколько разных пьес.

Во-первых, разница между объявлением массива как

int array[n];

а также

int* array = malloc(n * sizeof(int));

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

Причина того, что вторая версия работает здесь, заключается в деталях реализации того, как Си обычно компилируется. Как правило, память C разбита на несколько областей, включая стек (для вызовов функций и локальных переменных) и кучу (для объектов malloced). Стек обычно имеет гораздо меньший размер, чем куча; обычно это что-то вроде 8 МБ. В результате, если вы попытаетесь выделить огромный массив с

int array[n];

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

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

Надеюсь это поможет! 

133
templatetypedef
int list[n]

Выделяет пространство для целых чисел n в стеке , который обычно довольно мал. Использование памяти в стеке намного быстрее, чем альтернатива, но оно довольно мало, и стек легко переполнить (т. Е. Выделить слишком много памяти), если вы делаете такие вещи, как выделение огромных массивов или слишком глубокую рекурсию. Вам не нужно вручную освобождать память, выделенную таким образом, это делается компилятором, когда массив выходит из области видимости.

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

8
Seth Carnegie

int list [n] хранит данные в стеке, а malloc хранит их в куче.

Стек ограничен, и там не так много места, а куча намного больше.

2
Asier Gutierrez

int list[n] - это VLA, который размещается в стеке, а не в куче. Вам не нужно освобождать его (он автоматически освобождается в конце вызова функции), и он быстро распределяется, но, как вы обнаружили, пространство для хранения очень ограничено. Вы должны выделить большие значения в куче.

1
Puppy

Это объявление выделяет память в стеке

    int list[n]

malloc выделяет в куче.

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

Смотрите также этот ответ для получения дополнительной информации

1
thumbmunkeys

Предполагая, что у вас есть типичная реализация в вашей реализации, наиболее вероятно, что:

int list[n]

выделенный список в вашем стеке, где как:

int *list = malloc(n*sizeof(int))

выделенная память на вашей куче. 

В случае стека обычно существует предел того, насколько велики они могут расти (если они вообще могут расти). В случае с кучей все еще есть предел, но он, как правило, в значительной степени и (в целом) ограничен вашим адресным пространством RAM + swap +, которое обычно по крайней мере на порядок больше, если не больше.

1
Flexo
   int array[n];

Это пример статически размещенного массива, и во время компиляции размер массива будет известен. И массив будет размещен в стеке.

   int *array(malloc(sizeof(int)*n);

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

0
cammando

Если вы работаете в Linux, вы можете установить для ulimit -s более высокое значение, и это также может работать для выделения стека ........ Когда вы выделяете память в стеке, эта память остается до конца выполнения вашей функции. Если вы выделяете память в куче (используя malloc), вы можете освободить память в любое время (даже до окончания выполнения вашей функции).

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

0
Manik Sidana

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

0
Tibor