Чтение онлайн

на главную - закладки

Жанры

Linux программирование в примерах
Шрифт:

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, '\0', 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
пустой указатель:

free(coordinates);

coordinates = NULL; /* не требуется, но хорошая мысль */

После вызова f

ree(coordinates)
доступ к памяти, на которую указывает
coordinates
, запрещен. Она теперь «принадлежит» процедурам выделения, и они могут поступать с ней как сочтут нужным. Они могут изменить содержимое памяти или даже удалить ее из адресного пространства процесса! Таким образом, есть несколько типичных ошибок, которых нужно остерегаться при использовании
free
:

Доступ к освобожденной памяти

Если она не была освобождена, переменная

coordinates
продолжает указывать на блок памяти, который больше не принадлежит приложению. Это называется зависшим указателем (dangling pointer). На многих системах вы можете уйти от наказания, продолжая использовать эту память, по крайней мере до следующего выделения или освобождения памяти. На других системах, однако, такой доступ не будет работать. В общем, доступ к освобожденной памяти является плохой мыслью: это непереносимо и ненадежно, и GNU Coding Standards отвергает его. По этой причине неплохо сразу же установить в указателе программы значение
NULL
. Если затем вы случайно попытаетесь получить доступ к освобожденной памяти, программа немедленно завершится с ошибкой нарушения сегментации (надеемся, до того, как вы успели вашу программу выпустить в свет).

Освобождение одного и того же указателя дважды

Это создает «неопределенное поведение». После передачи блока памяти обратно выделяющим процедурам они могут объединить освобожденный блок с другой свободной памятью, которая есть в их распоряжении. Освобождение чего-то уже освобожденного ведет к неразберихе и в лучшем случае к крушению; известно, что так называемые двойные освобождения приводили к проблемам безопасности.

Передача указателя, полученного не от функций

malloc
,
calloc
или
realloc

Это кажется очевидным, но тем не менее важно. Плоха даже передача указателя на адрес где-то в середине динамически выделенной памяти:

free(coordinates + 10);

/* Освободить все кроме первых 10 элементов */

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

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

Поделиться:
Популярные книги

Последний рейд

Сай Ярослав
5. Медорфенов
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Последний рейд

Кодекс Охотника. Книга XVIII

Винокуров Юрий
18. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XVIII

Сотник

Вязовский Алексей
2. Индийский поход
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Сотник

Идеальный мир для Лекаря 23

Сапфир Олег
23. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 23

Седина в бороду, Босс… вразнос!

Трофимова Любовь
Юмор:
юмористическая проза
5.00
рейтинг книги
Седина в бороду, Босс… вразнос!

Золото Советского Союза: назад в 1975

Майоров Сергей
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Золото Советского Союза: назад в 1975

Древесный маг Орловского княжества 3

Павлов Игорь Васильевич
3. Орловское княжество
Фантастика:
аниме
сказочная фантастика
фэнтези
попаданцы
гаремник
5.00
рейтинг книги
Древесный маг Орловского княжества 3

На границе империй. Том 10. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 4

Неудержимый. Книга XVII

Боярский Андрей
17. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XVII

Черный дембель. Часть 2

Федин Андрей Анатольевич
2. Черный дембель
Фантастика:
попаданцы
альтернативная история
4.25
рейтинг книги
Черный дембель. Часть 2

Воин

Бубела Олег Николаевич
2. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.25
рейтинг книги
Воин

Первый среди равных. Книга XII

Бор Жорж
12. Первый среди Равных
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Первый среди равных. Книга XII

Кодекс Крови. Книга IХ

Борзых М.
9. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга IХ

Газлайтер. Том 28

Володин Григорий Григорьевич
28. История Телепата
Фантастика:
боевая фантастика
аниме
попаданцы
5.00
рейтинг книги
Газлайтер. Том 28