- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
Наконец, упомянем потоки (threads), которые представляют несколько цепочек исполнения в рамках единственного адресного пространства. Обычно у каждого потока имеется свой собственный стек, а также способ получения локальных данных потока, т.е. динамически выделяемых данных для персонального использования этим потоком. Мы больше не будем рассматривать в данной книге потоки, поскольку это является продвинутой темой.
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 malloc(3):
#include <stdlib.h> /* ISO С */
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; /* какой у нас индекс? */
}
Заголовочный файл <stdlib.h> объявляет множество стандартных библиотечных функций С и типов (таких, как size_t), он определяет также константу препроцессора NULL, которая представляет «нуль» или недействительный указатель. (Это нулевое значение, такое, как 0 или '((void*)0)'. Явное использование 0 относится к стилю С++; в С, однако, NULL является предпочтительным, мы находим его гораздо более читабельным для кода С.)
3.2.1.2. Начальное выделение памяти: malloc()
Сначала память выделяется с помощью malloc(). Передаваемое функции значение является общим числом затребованных байтов. Возвращаемое значение является указателем на вновь выделенную область памяти или NULL, если память выделить невозможно. В последнем случае для обозначения ошибки будет установлен errno. (errno является специальной переменной, которую системные вызовы и библиотечные функции устанавливают для указания произошедшей ошибки. Она описывается в разделе 4.3 «Определение ошибок».) Например, предположим, что мы хотим выделить переменное число некоторых структур. Код выглядит примерно так:
struct coord { /* 3D координаты */
int x, y, z;
} *coordinates;
unsigned int count; /* сколько нам нужно */
size_t amount; /* общий размер памяти */
/* ... как-нибудь определить нужное число... */
amount = count * sizeof(struct coord); /* сколько байт выделить */
coordinates = (struct coord*)malloc(amount); /* выделить память */
if (coordinates == NULL) {
/* сообщить об ошибке, восстановить или прервать */
}
/* ... использовать координаты... */
Представленные здесь шаги являются стереотипными. Порядок следующий:
1. Объявить указатель соответствующего типа для выделенной памяти.
2. Вычислить размер выделяемой памяти в байтах. Для этого нужно умножить число нужных объектов на размер каждого из них. Последний получается с помощью оператора С sizeof, который для этой цели и существует (наряду с другими). Таким образом, хотя размер определенной структуры среди различных компиляторов и архитектур может различаться, sizeof всегда возвращает верное значение, а исходный код остается правильным и переносимым.
При выделении массивов для строк символов или других данных типа char нет необходимости умножения на sizeof(char), поскольку последнее по определению всегда равно 1. Но в любом случае это не повредит.
3. Выделить память с помощью malloc(), присвоив возвращаемое функцией значение переменной указателя. Хорошей практикой является приведение возвращаемого malloc() значения к типу переменной, которой это значение присваивается. В С этого не требуется (хотя компилятор может выдать предупреждение). Мы настоятельно рекомендуем всегда приводить возвращаемое значение.
Обратите внимание, что на C++ присвоение знамения указателя одного типа указателю другого типа требует приведения типов, какой бы ни был контекст. Для управления динамической памятью программы C++ должны использовать new и delete, а не malloc() и free(), чтобы избежать проблем с типами.
4. Проверить возвращенное значение. Никогда не предполагайте, что выделение памяти было успешным. Если выделение памяти завершилось неудачей, malloc() возвращает NULL. Если вы используете значение без проверки, ваша программа может быть немедленно завершена из-за нарушения сегментации (segmentation violation), которое является попыткой использования памяти за пределами своего адресного пространства.
Если вы проверите возвращенное значение, вы можете по крайней мере выдать диагностическое сообщение и корректно завершить программу. Или можете попытаться использовать какой-нибудь другой способ восстановления.
Выделив блок памяти и установив в coordinates указатель на него, мы можем затем интерпретировать coordinates как массив, хотя он в действительности указатель:
int cur_x, cur_y, cur_z;
size_t an_index;
an_index = something;
cur_x = coordinates[an_index].x;
cur_y = coordinates[an_index].y;
cur_z = coordinates[an_index].z;
Компилятор создает корректный код для индексирования через указатель при получении доступа к членам структуры coordinates[an_index].
ЗАМЕЧАНИЕ. Блок памяти, возвращенный malloc(), не инициализирован. Он может содержать любой случайный мусор. Необходимо сразу же инициализировать память нужными значениями или хотя бы нулями. В последнем случае используйте функцию memset() (которая обсуждается в разделе 12.2 «Низкоуровневая память, функции memXXX()):
memset(coordinates, ' ', amount);
Другой возможностью является использование calloc(), которая вскоре будет описана.
Джефф Колье (Geoff Collyer) рекомендует следующую методику для выделения памяти:
some_type *pointer;
pointer = malloc(count * sizeof(*pointer));
Этот подход гарантирует, что malloc() выделит правильное количество памяти без необходимости смотреть объявление pointer. Если тип pointer впоследствии изменится, оператор sizeof автоматически гарантирует, что выделяемое число байтов остается правильным. (Методика Джеффа опускает приведение типов, которое мы только что обсуждали. Наличие там приведения типов также гарантирует диагностику, если тип pointer изменится, а вызов malloc() не будет обновлен.)
3.2.1.3. Освобождение памяти: free()
Когда вы завершили использование памяти, «верните ее обратно», используя функцию free(). Единственный аргумент является указателем, предварительно полученным с использованием другой функции выделения. Можно (хотя это бесполезно) передать функции free() пустой указатель:

