Разница между типом массива и массивом, выделенным с помощью malloc - программирование
Подтвердить что ты не робот

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

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

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

int list[n]

и, наконец, цикл for из n с fscanf.

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

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

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

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

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

4b9b3361

Ответ 1

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

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

int array[n];

и

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

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

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

int array[n];

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

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

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

Ответ 2

int list[n]

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

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

Ответ 3

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

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

Ответ 4

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

Ответ 6

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

int list[n]

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

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

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

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

Ответ 7

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

Ответ 8

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

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

Ответ 9

   int array[n];

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

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

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