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

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

Жанры

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
пытается использовать эту информацию, она обнаружит там недействительные данные. В других реализациях, где учетная информация хранится в конце выделенного блока; возникают те же проблемы.)

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

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

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

Звездная Кровь. Экзарх III

Рокотов Алексей
3. Экзарх
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Экзарх III

Афганский рубеж 2

Дорин Михаил
2. Рубеж
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Афганский рубеж 2

Бояръ-Аниме. Газлайтер. Том 34

Володин Григорий Григорьевич
34. История Телепата
Фантастика:
фэнтези
боевая фантастика
аниме
5.00
рейтинг книги
Бояръ-Аниме. Газлайтер. Том 34

Последний Паладин. Том 9

Саваровский Роман
9. Путь Паладина
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Последний Паладин. Том 9

Адвокат империи

Карелин Сергей Витальевич
1. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
фэнтези
5.75
рейтинг книги
Адвокат империи

Чужое наследие

Кораблев Родион
3. Другая сторона
Фантастика:
боевая фантастика
8.47
рейтинг книги
Чужое наследие

Миллионщик

Шимохин Дмитрий
3. Подкидыш
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Миллионщик

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

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

Тринадцатый IV

NikL
4. Видящий смерть
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Тринадцатый IV

Черный Маг Императора 13

Герда Александр
13. Черный маг императора
Фантастика:
попаданцы
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Черный Маг Императора 13

Хозяин оков VI

Матисов Павел
6. Хозяин Оков
Фантастика:
фэнтези
попаданцы
гаремник
5.00
рейтинг книги
Хозяин оков VI

Шаман

Седой Василий
5. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Шаман

Петля, Кадетский Корпус. Книга четвертая

Алексеев Евгений Артемович
4. Петля
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Петля, Кадетский Корпус. Книга четвертая