Программирование на C

malloc на языке c

malloc на языке c
Вы можете прийти сюда по двум причинам: либо вы хотите динамически распределять контент, либо хотите узнать больше о том, как работает malloc. В любом случае вы попали в нужное место! Динамическое распределение - это процесс, который происходит часто, но, как правило, мы не используем его сами: подавляющее большинство языков программирования управляют памятью за вас, так как это сложная работа, и если вы не сделаете это должным образом, возникнут проблемы с безопасностью.

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

Что такое динамическое размещение? Зачем мне нужен malloc?

Ну во всех приложениях при создании новой переменной - это часто называют объявлением переменной - тебе нужна память, чтобы хранить это. Поскольку ваш компьютер находится в наши дни, он может запускать более одного приложения одновременно, поэтому каждое приложение должно сообщать вашей ОС (здесь Linux) что ему нужен такой объем памяти. Когда вы пишете такой код:

#включать
#включать
#define DISK_SPACE_ARRAY_LENGTH 7
void getFreeDiskSpace (int statsList [], size_t listLength)
возвращаться;

int main ()
/ * Содержит свободное место на диске за последние 7 дней. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
вернуть EXIT_SUCCESS;

Массиву freeDiskSpace требуется память, поэтому вам нужно будет запросить разрешение Linux, чтобы получить немного памяти. Однако, как очевидно при чтении исходного кода, что вам понадобится массив из 7 int, компилятор автоматически запрашивает его у Linux, и он размещает его в стеке. Это в основном означает, что это хранилище уничтожается, когда вы возвращаете функцию, в которой объявлена ​​переменная. Вот почему вы не можете этого сделать:

#включать
#включать
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * ПОЧЕМУ МЫ ЭТО ДЕЛАЕМ?! statsList будет УНИЧТОЖЕН! * /
return statsList;

int main ()
/ * Содержит свободное место на диске за последние 7 дней. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
вернуть EXIT_SUCCESS;

Теперь ты видишь проблему легче? Затем вы хотите объединить две строки. В Python и JavaScript вы бы сделали:

newStr = str1 + str2

Но, как известно, в C так не работает. Итак, чтобы создать URL-адрес, например, вам необходимо объединить две строки, такие как путь URL-адреса и имя домена. В C у нас есть strcat, верно, но он работает только в том случае, если у вас есть массив, в котором достаточно места для него.

У вас возникнет соблазн узнать длину новой строки с помощью strlen, и вы будете правы. Но тогда как бы вы попросили Linux зарезервировать этот неизвестный объем памяти?? Компилятор не может вам помочь: точное пространство, которое вы хотите выделить, известно только во время выполнения. Это именно то место, где вам нужно динамическое размещение, а malloc.

Написание моей первой функции на C с использованием malloc

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

У вас всего 3 обязанности:

  1. Проверьте, возвращает ли malloc NULL. Это происходит, когда Linux не хватает памяти для предоставления.
  2. Освободите неиспользуемые переменные. В противном случае вы потратите впустую память, и это замедлит работу вашего приложения.
  3. Никогда не используйте зону памяти после того, как вы освободили переменную.

Если вы будете следовать всем этим правилам, все будет хорошо, а динамическое размещение решит многие проблемы. Поскольку вы выбираете, когда вы освобождаете память, вы также можете безопасно вернуть переменную, выделенную с помощью malloc. Просто не забудьте освободить его!

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

Позвольте мне показать вам на примере concat:

#включать
#включать
#включать
/ *
* При вызове этой функции не забудьте проверить, является ли возвращаемое значение NULL
* Если это не NULL, вы должны вызвать free для возвращаемого указателя после того, как значение
* больше не используется.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/ * Проверка безопасности. * /
if (baseUrl == NULL || toolPath == NULL)
return NULL;

finalUrlLen = strlen (baseUrl) + strlen (toolPath);
/ * Не забывайте '\ 0', поэтому + 1. * /
finalUrl = malloc (sizeof (char) * (finalUrlLen + 1));
/ * Следуя правилам malloc… * /
if (finalUrl == NULL)
return NULL;

strcpy (finalUrl, baseUrl);
strcat (finalUrl, toolPath);
return finalUrl;

int main ()
char * googleImages = NULL;
googleImages = getUrl ("https: // www.Google.com "," / imghp ");
if (googleImages == NULL)
вернуть EXIT_FAILURE;

put ("URL-адрес инструмента:");
помещает (googleImages);
/ * Это больше не нужно, освободите его. * /
бесплатно (googleImages);
googleImages = NULL;
вернуть EXIT_SUCCESS;

Итак, вы видите практический пример использования динамического распределения. Во-первых, я избегаю ловушек, таких как предоставление возвращаемого значения getUrl прямо в функцию put. Затем я также нахожу время, чтобы прокомментировать и задокументировать тот факт, что возвращаемое значение должно быть освобождено должным образом. Я также везде проверяю значения NULL, чтобы можно было безопасно отловить все неожиданное, вместо того, чтобы приводить к сбою приложения.

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

Вы можете заметить, что я использовал sizeof в malloc. Он позволяет узнать, сколько байтов использует символ, и проясняет намерение в коде, чтобы он был более читабельным. Для char sizeof (char) всегда равен 1, но если вместо этого вы используете массив int, он работает точно так же. Например, если вам нужно зарезервировать 45 int, просто выполните:

fileSizeList = malloc (sizeof (int) * 45);

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

Как работает malloc под капотом?

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

Фактически Linux предоставляет два способа увеличить объем памяти: sbrk и mmap. У обоих есть ограничения, и одно из них: вы можете выделить только относительно большие объемы, например 4096 байт или 8192 байта. Вы не можете запросить 50 байтов, как в примере, но вы также не можете запросить 5894 байта.

Здесь есть объяснение: Linux необходимо вести таблицу, в которой указывается, какое приложение зарезервировало какую зону памяти. И эта таблица также использует пространство, поэтому, если для каждого байта требуется новая строка в этой таблице, потребуется большая доля памяти. Вот почему память разделена на большие блоки, например, по 4096 байт, и так же, как вы не можете купить 2 с половиной апельсина в продуктовом магазине, вы не можете попросить половину блоков.

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

Но malloc умен: если вы вызываете malloc для выделения 16 MiB или большого количества, malloc, вероятно, запросит у Linux полные блоки, выделенные только для этой большой переменной, используя mmap. Таким образом, когда вы звоните бесплатно, вы с большей вероятностью сможете избежать ненужной траты места. Не волнуйтесь, malloc лучше справляется с переработкой мусора, чем люди!

Заключение

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

Как установить Doom и играть в него в Linux
Введение в Doom Серия Doom возникла в 90-х годах после выхода оригинальной Doom. Это мгновенно стал хитом, и с тех пор серия игр получила множество на...
Vulkan для пользователей Linux
С каждым новым поколением видеокарт мы видим, как разработчики игр расширяют границы графической точности и приближаются на шаг ближе к фотореализму. ...
OpenTTD против Simutrans
Создание собственного транспортного симулятора может быть увлекательным, расслабляющим и чрезвычайно увлекательным занятием. Вот почему вам нужно попр...