Выделение с инициализацией нулями: — КиберПедия 

Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...

Выделение с инициализацией нулями:

2021-01-29 114
Выделение с инициализацией нулями: 0.00 из 5.00 0 оценок
Заказать работу

 

Функция является простой оболочкой вокруг. Главным ее преимуществом является то, что она обнуляет динамически выделенную память. Она также вычисляет за вас размер памяти, принимая в качестве параметра число элементов и размер каждого элемента:

 

По крайней мере идейно, код довольно простой. Вот одна из возможных реализаций:

 

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

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

 

Подведение итогов из GNU Coding Standards

 

Чтобы подвести итоги, процитируем, что говорит об использовании процедур выделения памяти GNU Coding Standards:

 

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

В Unix может разрушить блок памяти, если она возвращает ноль. GNU не содержит подобной ошибки: если она завершается неудачей, исходный блок остается без изменений. Считайте, что ошибка устранена. Если вы хотите запустить свою программу на Unix и хотите избежать потерь в этом случае, вы можете использовать GNU.

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

 

В этих трех коротких абзацах Ричард Столмен (Richard Stallman) выразил суть важных принципов управления динамической памятью с помощью. Именно использование динамической памяти и принцип «никаких произвольных ограничений» делают программы GNU такими устойчивыми и более работоспособными по сравнению с их Unix‑двойниками.

Мы хотим подчеркнуть, что стандарт С требует, чтобы не разрушал оригинальный блок памяти, если она возвращает.

 

Использование персональных программ распределения

 

Набор функций с является набором общего назначения по выделению памяти. Он должен быть способен обработать запросы на произвольно большие или маленькие размеры памяти и осуществлять все необходимые учетные действия при освобождении различных участков выделенной памяти. Если ваша программа выделяет значительную динамическую память, вы можете обнаружить, что она тратит большую часть своего времени в функциях.

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

Например, GNU awk (gawk) использует эту методику. Выдержка из файла в дистрибутиве (слегка отредактировано, чтобы уместилось на странице):

 

 

Переменная указывает на связанный список структур NODE. Макрос убирает из списка первую структуру, если она там есть. В противном случае она вызывает, чтобы выделить новый список свободных структур. Макрос освобождает структуру, помещая его в начало списка.

 

ЗАМЕЧАНИЕ. Первоначально при написании своего приложения делайте это простым способом: непосредственно используйте и. Написание собственного распределителя вы должны рассмотреть лишь в том и только в том случае, если профилирование вашей программы покажет, что она значительную часть времени проводит в функциях выделения памяти.

 

 

Пример: чтение строк произвольной длины

 

Поскольку это, в конце концов, Программирование на Linux в примерах, настало время для примера из реальной жизни. Следующий код является функцией из GNU Make 3.80 (). Ее можно найти в файле.

Следуя принципу «никаких произвольных ограничений», строки в могут быть любой длины. Поэтому главной задачей этой процедуры является чтение строк произвольной длины и гарантирование того, что они помещаются в используемый буфер.

Вторичной задачей является распоряжение продлением строк. Как и в С, строки, заканчивающиеся обратным слешем, логически продолжаются со следующей строки. Используется стратегия поддержания буфера. В нем хранится столько строк, сколько помещается в буфер, причем указатели отслеживают начало буфера, текущую строку и следующую строку. Вот структура:

 

 

Поле отслеживает размер всего буфера, a является указателем типа для файла ввода. Структура floc не представляет интереса при изучении процедуры.

Функция возвращает число строк в буфере. (Номера строк здесь даны относительно начала функции, а не исходного файла.)

 

Для начала заметим, что GNU Make написан на С K&R для максимальной переносимости. В исходной части объявляются переменные, и если ввод осуществляется из строки (как в случае расширения макроса), код вызывает другую функцию, (строки 13 и 14). Строка '' (строка 13) является более короткой (и менее понятной, по нашему мнению) проверкой на пустой указатель; это то же самое, что и ''.

Строки 19‑21 инициализируют указатели и вводят байт NUL, который является символом завершения строки С в конце буфера. Затем функция входит в цикл (строки 23–95), который продолжается до завершения всего ввода.

 

Функция (строка 23) принимает указатель на буфер, количество байтов для прочтения и переменную для файла, из которого осуществляется чтение. Она читает на один байт меньше указанного, чтобы можно было завершить буфер символом ''. Эта функция подходит, поскольку она позволяет избежать переполнения буфера. Она прекращает чтение, когда встречается с символами конца строки или конца файла; если это символ новой строки, он помещается в буфер. Функция возвращает при неудаче или значение указателя первого аргумента при успешном завершении.

В этом случае аргументами являются указатель на свободную область буфера, размер оставшейся части буфера и указатель для чтения.

Комментарии в строках 32–36 очевидны; если встречается нулевой байт, программа выводит сообщение об ошибке и представляет вывод как пустую строку. После компенсирования нулевого байта (строки 30–41) код продолжает работу.

 

 

Строки 43–52 увеличивают указатель на участок буфера за только что прочитанными данными. Затем код проверяет, является ли последний прочитанный символ символом конца строки. Конструкция (строка 48) проверяет символ перед p, также как является текущим символом, а – следующим. Сначала это кажется странным, но если вы переведете это на язык математики указателей,, это приобретет больший смысл, а индексированная форма, возможно, проще для чтения.

Если последний символ не был символом конца строки, это означает, что нам не хватило места, и код выходит (с помощью) для увеличения размера буфера (строка 49). В противном случае увеличивается число строк.

 

Строки 54–62 обрабатывают вводимые строки, следующие соглашению Microsoft по завершению строк комбинацией символов возврата каретки и перевода строки (CR‑LF), а не просто символом перевода строки (новой строки), который является соглашением Linux/Unix. Обратите внимание, что исключает этот код на платформе Microsoft, очевидно, библиотека на этих системах автоматически осуществляет это преобразование. Это верно также для других не‑Unix систем, поддерживающих стандартный С.

 

 

До сих пор мы имели дело с механизмом получения в буфер по крайней мере одной полной строки. Следующий участок обрабатывает случай строки с продолжением. Хотя он должен гарантировать, что конечный символ обратного слеша не является частью нескольких обратных слешей в конце строки. Код проверяет, является ли общее число таких символов четным или нечетным путем простого переключения переменной из 0 в 1 и обратно. (Строки 64–70.)

Если число четное, условие '' (строка 72) будет истинным. В этом случае конечный символ конца строки замещается байтом NUL, и код выходит из цикла.

С другой стороны, если число нечетно, строка содержит четное число пар обратных слешей (представляющих символы \\, как в С), и конечную комбинацию символов обратного слеша и конца строки.[43] В этом случае, если в буфере остались по крайней мере 80 свободных байтов, программа продолжает чтение в цикле следующей строки (строки 78–81). (Использование магического числа 80 не очень здорово; было бы лучше определить и использовать макроподстановку.)

По достижении строки 83 программе нужно больше места в буфере. Именно здесь вступает в игру динамическое управление памятью. Обратите внимание на комментарий относительно сохранения значения (строки 83‑84); мы обсуждали это ранее в терминах повторной инициализации указателей для динамической памяти. Значение end также устанавливается повторно. Строка 89 изменяет размер памяти.

Обратите внимание, что здесь вызывается функция. Многие программы GNU используют вместо и функции‑оболочки, которые автоматически выводят сообщение об ошибке и завершают программу, когда стандартные процедуры возвращают. Такая функция‑оболочка может выглядеть таким образом:

 

 

Таким образом, если функция возвращается, она гарантированно возвращает действительный указатель. (Эта стратегия соответствует принципу «проверки каждого вызова на ошибки», избегая в то же время беспорядка в коде, который происходит при таких проверках с непосредственным использованием стандартных процедур.) Вдобавок, это позволяет эффективно использовать конструкцию '', против которой мы предостерегали ранее.

Обратите внимание, что не всегда подходит использование такой оболочки. Если вы сами хотите обработать ошибки, не следует использовать оболочку. С другой стороны, если нехватка памяти всегда является фатальной ошибкой, такая оболочка вполне удобна.

 

 

В заключение, функция проверяет ошибки ввода/вывода, а затем возвращает описательное значение. Функция (строка 98) не возвращается.[44]

 


Поделиться с друзьями:

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰)...

Наброски и зарисовки растений, плодов, цветов: Освоить конструктивное построение структуры дерева через зарисовки отдельных деревьев, группы деревьев...

Состав сооружений: решетки и песколовки: Решетки – это первое устройство в схеме очистных сооружений. Они представляют...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.022 с.