Общий размер загруженного в память из файла в 12 320 байтов всего лишь 1742 байта. Большую часть этого места занимают strip
удаляет символы из объектного файла. Для большой программы это может сохранить значительное дисковое пространство ценой невозможности отладки дампа ядра[40], если таковой появится (На современных системах об этом не стоит беспокоиться, не используйте strip
.) Даже после удаления символов файл все еще больше, чем загруженный в память образ, поскольку формат объектного файла содержат дополнительные данные о программе, такие, как использованные разделяемые библиотеки, если они есть.[41]
Наконец, упомянем
3.2. Выделение памяти
Четыре библиотечные функции образуют основу управления динамической памятью С Мы опишем сначала их, затем последуют описания двух системных вызовов, поверх которых построены эти библиотечные функции. Библиотечные функции С, в свою очередь, обычно используются для реализации других выделяющих память библиотечных функций и операторов C++ new
и delete
.
Наконец, мы обсудим функцию, которую часто используют, но которую мы не рекомендуем использовать.
3.2.1. Библиотечные вызовы: malloc()
, calloc()
, realloc()
, free()
Динамическую память выделяют с помощью функций malloc()
или calloc()
. Эти функции возвращают указатели на выделенную память. Когда у вас есть блок памяти определенного первоначального размера, вы можете изменить его размер с помощью функции realloc()
. Динамическая память освобождается функцией free()
.
Отладка использования динамической памяти сама по себе является важной темой. Инструменты для этой цели мы обсудим в разделе 15.5.2 «Отладчики выделения памяти».
3.2.1.1. Исследование подробностей на языке С
Вот объявления функций из темы справки GNU/Linux
#include
void *calloc(size_t nmemb, size_t size);
/* Выделить и инициализировать нулями */
void *malloc(size_t size);
/* Выделить без инициализации */
void free(void *ptr);
/* Освободить память */
void *realloc(void *ptr, size_t size);
/* Изменить размер выделенной памяти */
Функции выделения памяти возвращают тип void*
. Это бестиповый или общий указатель, все, что с ним можно делать — это привести его к другому типу и назначить типизированному указателю. Примеры впереди.
Тип size_t
является беззнаковым целым типом, который представляет размер памяти. Он используется для динамического выделения памяти, и далее в книге мы увидим множество примеров его использования. На большинстве современных систем size
_t является unsigned long
, но лучше явно использовать size_t
вместо простого целого типа unsigned
.
Тип ptrdiff_t
используется для вычисления адреса в арифметике указателей, как в случае вычисления указателя в массиве:
#define MAXBUF ...
char *p;
char buf[MAXBUF];
ptrdiff_t where;
p = buf;
while (/* некоторое условие */) {
...
p += something;
...
where = p - buf; /* какой у нас индекс? */
}
Заголовочный файл
объявляет множество стандартных библиотечных функций С и типов (таких, как size_t
), он определяет также константу препроцессора NULL
, которая представляет «нуль» или недействительный указатель. (Это нулевое значение, такое, как 0 или '((void*)0)
'. Явное использование 0 относится к стилю С++; в С, однако, NULL
является предпочтительным, мы находим его гораздо более читабельным для кода С.)
3.2.1.2. Начальное выделение памяти: malloc()