В чем преимущество malloc?

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

подобно

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

/* Initialize LIS values for all indexes */
for ( i = 0; i < n; i++ )
lis[i] = 1;

мы могли бы использовать обычный массив.

Ну, я не совсем понимаю, как работает malloc, что на самом деле делает. Поэтому объяснение их было бы более полезным для меня.

И предположим, что мы заменим sizeof(int) * n просто n в приведенном выше коде, а затем попробуйте сохранить целочисленные значения, с какими проблемами я могу столкнуться? И есть ли способ напечатать значения, хранящиеся в переменной, непосредственно из выделенного пространства памяти, например, здесь это lis?

2

Решение

Ваш вопрос скорее сравнивает динамически размещенные массивы в стиле C с массивами переменной длины, что означает, что это может быть то, что вы ищете: Почему массивы переменной длины не являются частью стандарта C ++?

Тем не менее тег дает окончательный ответ: использование std::vector объект вместо

Пока это возможно, избегайте динамического выделения и ответственности за уродливое управление памятью ~> вместо этого попробуйте воспользоваться объектами с автоматической продолжительностью хранения. Еще одно интересное чтение может быть: Понимание значения термина и концепции — RAII (Приобретение ресурсов — Инициализация)


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

6

Другие решения

Более фундаментально, я думаю, кроме проблем стека против кучи и переменных против констант (и того факта, что вы не должны использовать malloc() в C ++, для начала), это то, что локальный массив перестает существовать при выходе из функции. Если вы вернете указатель на него, этот указатель станет бесполезным, как только получатель получит его, тогда как память динамически выделяется с помощью malloc() или же new все еще будет в силе. Вы не могли бы реализовать такую ​​функцию, как strdup() например, используя локальный массив, или разумно реализовать связанный список представлений или дерево.

3

Ответ прост. Местный1 В вашем стеке располагаются массивы, которые представляют собой небольшую предварительно выделенную память для вашей программы. Помимо пары тысяч данных, вы не можете сделать много в стеке. Для больших объемов данных вам нужно выделить память из стека.

Это то, что malloc делает.

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

Чтение значений из памяти (например, для печати) аналогично чтению из массива. Например printf("%d", list[5]);,

До C99 (я знаю, что вопрос помечен C ++, но, вероятно, вы изучаете C-compiled-in-C ++), была и другая причина. Не было никакого способа получить массив переменной длины в стеке. (Даже сейчас массивы переменной длины в стеке не так полезны, так как стек небольшой). Вот почему для переменного объема памяти, вам нужно было malloc Функция для выделения памяти настолько большой, насколько вам нужно, размер которой определяется во время выполнения.

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

Пример mallocобъекты FILEs. Как только вы позвоните fopenструктура, которая содержит данные, относящиеся к открытому файлу, динамически распределяется с использованием malloc и возвращается как указатель (FILE *).


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

2

Я полагаю, вы спрашиваете, какова цель с maloc():
Допустим, вы хотите получить данные от пользователя и выделить массив такого размера:

int n;
scanf("%d",&n);
int arr[n];

Это не удастся, потому что n не доступен во время компиляции. Сейчас начнется malloc()
Вы можете написать:

int n;
scanf("%d",&n);
int* arr = malloc(sizeof(int)*n);

На самом деле malloc() динамически распределять память в области кучи

1

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

  • Размер статического массива устанавливает жесткий верхний предел количества данных, которые программа может обрабатывать в любой момент времени без перекомпиляции. Если вы когда-нибудь пытались сделать что-то сложное в TeX и получили сообщение «Превышена емкость, извините», вот почему.
  • Операционная система (как она была) должна была зарезервировать пространство для статического массива сразу, независимо от того, будет ли он использоваться. Это явление привело к «чрезмерной загрузке», при которой ОС симулирует выделить всю память, которую вы, возможно, захотите, но затем убивает ваш процесс, если вы на самом деле пытаетесь использовать больше, чем доступно. Зачем кому-то этого хотеть? И все же это было раскрученный как особенность в середине 90-х коммерческий Unix, потому что это означало, что гигантские симуляции FORTRAN, которые потенциально Потребовалось гораздо больше памяти, чем было у вашей маленькой маленькой рабочей станции Sun, и без проблем можно было протестировать ее на небольших экземплярах. (Предположительно, вы бы запустить большой экземпляр на Cray где-то, что на самом деле было достаточно памяти, чтобы справиться.)
  • Динамические распределители памяти сложно реализовать Что ж. Посмотрите на бумага из джемлока почувствовать, насколько волосатым это может быть. (Если вы хотите автоматическую сборку мусора это становится еще сложнее.) Это именно то, что вы хотите, чтобы гуру кодировал один раз для всеобщего блага.

Так что в настоящее время даже довольно скромные встроенные среды дают вам своего рода динамический распределитель.

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

Однако, однако, не использование динамического выделения памяти, когда это действительно необходимо, может привести к собственным проблемам, таким как наложение жестких верхних ограничений на длину строк или включение невмешательства в ваш API (сравните gethostbyname в getaddrinfo).

Поэтому вы должны тщательно обдумать это.

0

мы могли бы использовать обычный массив

В C ++ (по крайней мере, в этом году) массивы имеют статический размер; поэтому создаем его из значения времени выполнения:

int lis[n];

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

В C это означало бы возиться с malloc; но вы спрашиваете о C ++, так что вы хотите

std::vector<int> lis(n, 1);

выделить массив размера n содержащий int значения инициализированы до 1.

(Если хотите, вы можете выделить массив new int[n]и не забудьте освободить его delete [] lis когда вы закончите, и будьте особенно осторожны, чтобы не просочиться, если выдается исключение; но жизнь слишком коротка для этой ерунды.)

Ну, я не совсем понимаю, как работает malloc, что на самом деле делает. Поэтому объяснение их было бы более полезным для меня.

malloc в С и new в C ++ выделяют постоянную память из «свободного хранилища». В отличие от памяти для локальных переменных, которая освобождается автоматически, когда переменная выходит из области видимости, она сохраняется до тех пор, пока вы не освободите ее явно (free в С, delete в C ++). Это необходимо, если вам нужен массив, чтобы пережить текущий вызов функции. Также неплохо, если массив очень большой: локальные переменные (как правило) хранятся в стеке с ограниченным размером. Если это переполнится, программа потерпит крах или иным образом пойдет не так. (И в текущем стандарте C ++ это необходимо, если размер не является константой времени компиляции).

И предположим, что мы заменим sizeof(int) * n просто n в приведенном выше коде, а затем попробуйте сохранить целочисленные значения, с какими проблемами я могу столкнуться?

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

И есть ли способ напечатать значения, хранящиеся в переменной, непосредственно из выделенного пространства памяти, например, здесь это lis?

Вы имеете в виду что-то вроде этого?

for (i = 0; i < len; ++i) std::cout << lis[i] << '\n';
0
По вопросам рекламы [email protected]