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

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

У нас также был файл ac с очень простым «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))?

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

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

 int array[n]; 

а также

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

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

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

 int array[n]; 

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

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

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

 int list[n] 

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

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

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

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

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

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

  int list[n] 

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

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

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

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

 int list[n] 

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

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

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

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

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

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

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

  int array[n]; 

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

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

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

  • Массив Unnest на один уровень
  • Установка указателя на произвольный размерный массив?
  • Массивы указателей функций в Фортране
  • Преобразование Mat в массив / вектор в OpenCV
  • Java Arrays.asList на примитивном типе массива создает неожиданный тип списка
  • `Array ()` vs `new Array ()`
  • Ссылка на строку в ресурсе массива строк с помощью xml
  • Являются ли массивы переданы по значению или переданы по ссылке в Java?
  • Доступ к случайному элементу в списке
  • Является ли массив примитивов Java хранимым в стеке или куче?
  • .NET / C # - преобразовать char в строку
  • Давайте будем гением компьютера.