Добавить в избранное | Сделать стартовой страницей

Большая Linux библиотека для пользователей OS Linux и ПО для нее
Есть что сказать? Нужен совет? Посети наш форум.




Библиотека языка C GNU glibc. часть 1

Автор : Сандра Лузмор, Ричард Сталлман, Роланд Макграх, Андрей Орам.

1. Введение

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

Библиотека GNU C, описанная в этом документе, содержит описание всех библиотечных функций, которые определены в соответствии c ANSI C стандартом, учитывая дополнительные особенности, специфические для POSIX-стандарта операционной системы UNIX, и расширений, специфических для GNU-разработок.

Цель этого руководства состоит в том, чтобы сообщить Вам, как использовать средства GNU библиотеки. Мы упомянули особенности ее стандартов, чтобы помочь Вам разобраться с вещами, которые являются потенциально непереносимыми на другие системы. Но переносимость не является основным вопросом данного руководства.

1.1 Начало

Это руководство написано с учетом того, что Вы по крайней мере немного знакомы с языком программирования C и базисными понятиями программирования. Вообще считается, что стандарт ANSI C (см. раздел 1.2.1 [ANSI C]) проще для понимания, чем "традиционные", предшествующие ANSI C, диалекты.

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

1.2 Стандарты и переносимость

Этот раздел обсуждает различные стандарты и другие источники, на которых базируется GNU C. Эти источники включают стандарты ANSI и POSIX, а так же реализации System V и Berkeley Unix.

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

См. Приложение B [Обзор библиотеки], для получения алфавитного списка функций и других символов, обеспечиваемых библиотекой. Этот список указывает также, на какие стандарты опирается каждая функция или символ.

ANSI C

Библиотека GNU C совместима со стандартом C, принятым Американским Институтом Национальных Стандартов (ANSI): American National Standard X3.159-1989_"ANSI C". Заголовочные файлы и библиотечные средства, которые составляют библиотеку GNU - надмножество средств, определенных в соответствии c ANSI C стандартом.

Библиотека GNU C

Если Вы следуете относительно строгой приверженности к ANSI C стандарту, Вы должны использовать опцию ` -ansi ', когда Вы компилируете ваши программы компилятором GNU C. Эта опция указывает, чтобы транслятор определил только возможности стандарта ANSI из библиотечных заголовочных файлов, если Вы явно не попросите о дополнительных особенностях, для получения информации относительно того, как это сделать см. раздел 1.3.4 [Макрокоманды установки возможностей].

Способность ограничить библиотеку, чтобы включить только возможности ANSI C важна, потому что ANSI C устанавливает ограничения, которым не удовлетворяют некоторые имена, определяемые библиотечной реализацией, т.е. GNU расширения не всегда удовлетворяют этим ограничениям. См. раздел 1.3.3 [Зарезервированные имена], где приводится более подробная информация относительно этих ограничений.

Это руководство не будет вдаваться в подробности различий между ANSI C и более старыми диалектами. Оно поможет вам написать программы, чтобы работать корректно под многими диалектами С, но не более.

Библиотека GNU также совместима с семейством стандартов IEEE POSIX, известных более формально как Переносной Интерфейс Операционной Системы. POSIX взят в основном из различных версий операционной системы UNIX.

Библиотечные средства, определенные POSIX стандартами ­ надмножество соответствующих cтандарту ANSI C; POSIX определяет дополнительные особенности для функций ANSI С, и задает определения новых дополнительных функций. Вообще предпочтение отдается скорее дополнительным требованиям и функциональным возможностям, определяемым POSIX стандартами, обеспечивающим поддержку низшего уровня для определенной среды операционной системы, чем общей поддержке языка программирования, который может выполняться в многих разнообразных средах операционной системы.

GNU C библиотека осуществляет все функции, определенные в IEEE Std 1003.1-1990, Системе Интерфейса Прикладных программ POSIX, обычно упоминающемся как POSIX.1. Первичные расширения к ANSI C средствам, определенные этими стандартными примитивами интерфейса файловой системы (см. Главу 9 [Интерфейс файловой системы]), зависят от устройства функции управления терминалом (см. Главу 12 [Интерфейс терминала низкого уровня]), и функции управления процессом (см. Главу 23 [Порожденнные процессы]).

Некоторые средства из IEEE Std 1003.2-1992, Стандарта Оболочки и Утилит POSIX (POSIX.2) также представлены в библиотеке GNU. Они включают в себя утилиты для обработки регулярных выражений и других средств сопоставления с образцом (см. Главу 16 [Сопоставления с образцом]).

Berkeley Unix

GNU C библиотека определяет средства (которые формально не стандартизированы) из некоторых версий UNIX: 4.2 BSD, 4.3 BSD, и 4.4 BSD Unix системы (также известной как Berkeley Unix) и из SunOS (популярной 4.2 BSD производной, которая включает некоторые функциональные возможности Unix System V ). Эта система поддерживает большинство ANSI и POSIX средств, 4.4 BSD и более новые выпуски SunOS, т.е. фактически поддерживает их все.

BSD средства включают символические связи (см. раздел 9.4 [Символические связи]), функцию выбора (см. раздел 8.6 [Ожидание ввода ­ вывода]), функции сигнала BSD (см. раздел 21.9 [BSD Обработка сигнала] ), и межпроцессорные связи (см. Главу 11 [Гнезда]).

SVID (Описание интерфейса System V)

Описание Интерфейса System V (SVID) - документ, описывающий AT&T операционную систему Unix System V. Это -, в некоторой степени, надмножество стандарта POSIX (см. раздел 1.2.2 [POSIX])

GNU C библиотека определяет некоторых из средств, требуемых SVID, и не требуемых в соответствии c ANSI или POSIX стандартами, для совместимости с Unix System V и другой UNIX системой (типа SunOS), которые включают эти средства. Однако, многие из большего количества менее известных и менее полезных средств, требуемых SVID не включены. (Фактически, Unix System V сама не обеспечивает их все.)

1.3 Использование библиотеки

Этот раздел описывает некоторые из практические проблемы использования GNU C библиотек.

Заголовочные файлы

Библиотеки используемые С программами на самом деле состоят из двух частей: заголовочные файлы, которые определяют типы и макрокоманды и объявляют переменные и функции; и фактическая библиотека или архив, который содержит определения переменных и функций.

( В Cи, описание просто представляет информацию,что функция или переменная существует, и присваивает ей тип. Для функционального объявления, нужно указать информацию относительно типов параметров. Цель объявлений состоит в том, чтобы транслятор правильно обработал ссылки к объявленным переменным и функциям. С другой стороны, определение фактически распределяет память для переменных или указывает, что делает функция.)

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

Файлы заголовка включаются в исходный файл директивой препроцессора "#include". Язык С поддерживает две формы этой директивы; первая,

      #include "header"
обычно используется, чтобы включить заголовочный файл header, который Вы пишете самостоятельно; он обычно содержит определения и объявления, описывающие интерфейсы между различными частями вашей конкретной прграммы. Другая форма,

      #include 
обычно используется, чтобы включить заголовочный файл "file.h" который содержит определения и объявления для стандартной библиотеки. Этот файл обычно устанавливается в стандартное место вашим администратором системы. Вы должны использовать эту вторую форму для файлов заголовка библиотеки C.

Обычно, директивы "#include" помещены в начале исходного С файла, перед любым другим кодом. Если Вы начинаете ваши исходные файлы некоторыми комментариями, объясняя, что код в файле делает, поместите директивы "#include" сразу после комментариев, согласно особенностям макроопределения (см. раздел 1.3.4 [Особенности макрокоманд] ).

Для получения подробной информации относительно использования заголовочных и директивы "#include" см. раздел "Заголовочные файлы" в Руководстве по препроцессору GNU C.

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

Некоторые библиотечные заголовочные файлы включают другие библиотечные заголовочные файлы. Однако, программируя в хорошем стиле, Вы не должны полагаться на это; лучше явно включить все заголовочные файлы, требуемые для библиотечных средств, которые Вы используете. GNU C библиотека была написана таким способом, что не имеет значения, включен ли заголовочный файл случайно больше чем один раз; при включении заголовочного файла второй раз ничего не происходит. Аналогично, если ваша программа многократно включает заголовочные файлы, порядок включения, не имеет значения.

Примечание относительно совместимости: включение стандартного заголовочного файла в любом порядке и любое число раз работает в любой ANSI C реализации. Однако, этого традиционно не было во многоих более старых C реализациях.

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

Макроопределения функций

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

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

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

  • Вы можете избегать макроопределения, включая имя функции в круглых скобках. Это работает, потому что имя функции не появляется в синтаксическом контексте, где оно распознаваемо как макрообращение.
  • Вы можете подавить любое макроопределение для целого исходного файла, используя директиву препроцессора "#undef ", если в явно описании средства не указано обратное.
Например, предположим, что заголовочный файл "stdlib.h" объявляет функцию abs как

      extern int abs ( int);
и также обеспечивает макроопределение для abs. Тогда при выполнении:

      #include < stdlib.h >
      int f ( int * i) {return (abs (++ * i));}
cсылка на abs может относиться или к макрокоманде или функции. С другой стороны, в каждом из следующих примеров производится ссылка на функцию, а не на макрос.

      #include < stdlib.h >
      int g ( int * i) {return ((abs) (++ * i));}
      #undef abs
      int h ( int *i) { return (abs (++*i)); }
Так как макроопределения, дублирующие функции, ведут себя в точно так же, как фактическая версия функции, удаление макроопределений обычно делает вашу программу медленнее.

Зарезервированные имена

Имена всех библиотечных типов, макрокоманд, переменных и функций, которые исходят из ANSI C стандарта, зарезервированы безоговорочно; ваша программа не имеет права переопределять эти имена. Все другие библиотечные имена зарезервированы, если ваша программа явно включает заголовочный файл, который определяет или объявляет их. Для этих ограничений имеются несколько причин:

  • Другие люди, читая ваш код могут запутаться, если Вы использовали функцию exit, чтобы делать что - нибудь полностью отличное от того, что делает стандартная функция выхода. Предотвращение этой ситуации помогает делать ваши программы более простыми, для понимания и способствует модульности.
  • Это лишает пользователя возможности случайно переопределить библиотечную функцию, которая вызывается в соответствии c другими библиотечными функциями. Если переопределение позволялось, те другие функции не будут работать.
  • Это позволяет транслятору делать любые специальные оптимизации опираясь на обращения к этим функциям, без риска, что они могут быть переопределены пользователем. Некоторые библиотечные средства, такие как variadic функции (с переменным числом аргументов, см. раздел A.2 [Variadic функции]) и нелокальные выходы (см. Главу 20 [Нелокальные выходы]), фактически требуют более близкого сотрудничества с частью C транслятора, и для транслятора проще обрабатывать их как встроенные части языка.
В дополнение к именам, описываемым в этом руководстве, зарезервированные имена включают в себя все внешние идентификаторы (глобальные функции и переменные) начинающиеся с подчеркивания ("_") и все идентификаторы независимо от использования, которые начинаются с двух подчеркиваний, или с подчеркивания сопровождаемого заголовочной буквой. Это для того, чтобы библиотека и заголовочные файлы могли определять функции, переменные, и макрокоманды для внутренних целей без риска конфликта с именами в программах пользователя.

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

  • Имена, начинающиеся с прописной буквы "E" с последующей цифрой, или символом верхнего регистра могут использоваться для дополнительных имен кода ошибки. См. Главу 2 [Сообщения об ошибках].
  • Имена, которые начинаются с "is' или "к" сопровождаемые символом нижнего регистра, могут использоваться для дополнительного тестирования символа и функций преобразования. См. Главу 4 [Обработка символов].
  • Имена, которые начинаются с "LC_" с последующим символом верхнего регистра, могут использоваться для дополнительных макрокоманд, определяя атрибуты стандарта. См. Главу 19 [Положения].
  • Названия всех существующих функций математики (см. Главу 13 [Математика]) с прибавленным "f" или "l" зарезервированы для соответствующих функций, которые применяют к числам с плавающей точкой и параметрам двойной длины, соответственно.
  • Имена, которые начинаются с "SIG", сопровождаемые символом верхнего регистра, зарезервированы для дополнительных имен сигнала. См. раздел 21.2 [Стандартные сигналы].
  • Имена, которые начинаются с "SIG_" сопровождаемые символом верхнего регистра, зарезервированы для дополнительных действий сигнала. См. раздел 21.3.1 [Обработка видеосигнала].
  • Имена, начинающиеся со "str", "mem", или "wcs", сопровождаемые символом нижнего регистра, зарезервированы для дополнительной строки и функций массива. См. Главу 5 [Уилиты для работы со строками и массивами].
  • Имена, которые заканчиваются на "_t" зарезервированы для дополнительных имен типа.
Кроме того, некоторые индивидуальные заголовочные файлы резервируют имена вне тех, что они фактически определяют. Если ваша программа включает такой специфический заголовочный файл, то у Вас есть повод для беспокойства.
  • Заголовочный файл "dirent.h" резервирует имена с предстоящим "d_".
  • Заголовочный файл "fcntl.h" резервирует имена с предстоящими "l_", "F_", "O_", и "S_".
  • Заголовочный файл "grp.h" резервирует имена с предстоящим "gr_".
  • Заголовочный файл "limits.h" резервирует имена, с приписанным "_MAX".
  • Заголовочный файл "pwd.h" резервирует имена с предстоящим "pw_".
  • Заголовочный файл "signal.h" резервирует имена с предстоящим "sa_" и "SA_".
  • Заголовочный файл "sys/stat.h" резервирует имена с предстоящим "st_" и "S_".
  • Заголовочный файл "sys/times.h" резервирует имена с предстоящим "tms_".
  • Заголовочный файл "termios.h" резервирует имена с предстоящим "c_", "V", "I", "O", и "TC", а также имена с предстоящим "B", сопровождаемым цифрой.

Макрокоманды управления особенностями

Управляя макрокомандами, Вы определяете точный набор особенностей, доступный, когда при компиляции исходного файла.

Если Вы компилируете ваши программы, используя "gcc -ansi", Вы получаете только ANSI C библиотечные особенности, если Вы явно не запрашиваете дополнительные особенности, определяя одну или большее количество макрокоманд особенностей. См. раздел "Опции Команд GNU CC" в GNU CC Руководстве, для уточнения информации относительно опций GCC.

Вы должны определить эти макрокоманды, используя директивы препроцессора "#define" в начале ваших файлов. Эти директивы должны стоять перед любым #include заголовочного файла системы. Лучше всего указывать их самыми первыми в файле, только после комментариев. Вы могли бы также использовать опцию `-D' для GCC, но лучше, если Вы создаете исходные файлы с указанием их собственного значения замкнутым способом.

_POSIX_SOURCE (макрос)

Если Вы определяете эту макрокоманду, то функциональные возможности из стандарта POSIX.1 (Стандарт ИИЭРа 1003.1) доступны, также как все ANSI C средства.

_POSIX_C_SOURCE (макрос)

Если Вы определяете эту макрокоманду со значением 1, то будут определены функциональные возможности из стандарта POSIX.1 (Стандарт ИИЭР 1003.1). Если Вы определяете эту макрокоманду со значением 2, то станут доступны функциональные возможности из стандарта POSIX.1 и функциональные возможности из стандарта POSIX.2 (Стандарт ИИЭР 1003.2). Это - в дополнение к ANSI C средствам.

_BSD_SOURCE (макрос)

Если Вы определяете эту макрокоманду, включаются функциональные возможности 4.3 BSD Unix, также как ANSI C, POSIX.1, и POSIX.2.

Некоторые из особенностей происходящие от 4.3 BSD Unix конфликтуют с соответствующими особенностями, определенными стандартом POSIX.1. Если эта макрокоманда определена, 4.3 BSD определения, имеют больший приоритет чем POSIX определения.

Из-за некоторых конфликтов между 4.3 BSD и POSIX.1, Вы должны использовать специальную BSD библиотеку совместимости при компоновании программ, компилируемых для BSD совместимости. Т. к. некоторые функции должны быть определены двумя различными способами, один из них в нормальной библиотеке C, а другой в библиотеке совместимости. Если ваша программа определяет _BSD_SOURCE, Вы должны указать опцию "-lbsd-compat" транслятору или компоновщику при компоновании программы, чтобы он нашел функции в этой специальной библиотеке совместимости перед поиском их в нормальной библиотеке C.

_SVID_SOURCE (макрос)

Если Вы определяете эту макрокоманду, функциональные возможности из SVID, включены также как ANSI C, POSIX.1, и POSIX.2.

_GNU_SOURCE (макрос)

Если Вы определяете эту макрокоманду, включены все: ANSI C, POSIX.1, POSIX.2, BSD, SVID, и расширения GNU. В случаях, конфликтов POSIX.1 с BSD, POSIX определения берут верх.

Если Вы хотите получить полный эффект _GNU_SOURCE, но установить BSD определениям больший приоритет необходимо примеенить следующую последовательность определений:

      #define _GNU_SOURCE
      #define _BSD_SOURCE
      #define _SVID_SOURCE
Обратите внимание, что, если Вы делаете это, Вы должны компоновать вашу программу с BSD библиотекой совместимости, указывая опцию `­ lbsd-compat' транслятору или компоновщику. Обратите внимание: если Вы забудете сделать это, Вы можете получить очень странные ошибки во время выполнения.

Мы рекомендуем, чтобы Вы использовали _GNU_SOURCE в новых программах. Если Вы не определяете опцию `-ansi' для GCC и не определяете никакую из этих макрокоманд явнно, то _GNU_SOURCE дает тот же эффект.

Когда Вы определяете макрокоманду, чтобы запросить больший класс особенностей, безобидно определить кроме того макрокоманду для подмножества этих особенностей. Например, если Вы определяете _POSIX_ C_SOURCE, то определение _POSIX_SOURCE не имеет никакого эффекта. Аналогично, если Вы определяете _GNU_SOURCE, определяя затем либо _POSIX_SOURCE либо _POSIX_C_SOURCE либо _SVID_SOURCE, также не будет никакого эффекта.

Обратите внимание, что особенности _BSD_SOURCE не подмножество любой другой из обеспечиваемых макрокоманд особенностей. Потому что эта макрокоманда определяет особенности BSD, которые берут верх над особенностями POSIX, которые запрашиваются другими макрокомандами. По этой причине, определение _BSD_SOURCE в дополнение к другим макрокомандам особенностей заставляет особенности BSD брать верх при конфликтое с особенностями POSIX .

1.4 Путеводитель по руководству

Имеется краткий обзор содержания оставшихся глав этого руководства.

  • Глава 2 [Сообщения об ошибках], описывает, как сообщаются ошибки, обнаруженные при использовании библиотекой.
  • Глава 3 [Распределение памяти], описывает средства библиотеки GNU для динамического распределения памяти. Если Вы не знаете заранее сколько памяти потребует ваша программа , Вы можете распределять память динамически, и управлять этим через указатели.
  • Глава 4 [Обработка символов], содержит информацию относительно символьных функций классификаций (типа isspace) и функций для выполнения преобразования по выбору.
  • Глава 5 [Утилиты для работы со строками и массивами], имеет описания функций для управления строками (символьными массивами, завершенными пустым указателем) и общими массивами байтов, включая операции типа копирования и сравнения.
  • Глава 6 [Краткий обзор ввода - вывода], рассматривают средства ввода и вывода в библиотеке, и содержит информацию относительно базисных понятий, таких как имя файла.
  • Глава 7 [Потоки ввода - вывода], описывает операции ввода ­ вывода, включая потоки (или FILE* объекты). Это обычные библиотечные функции C из "stdio.h".
  • Глава 8 [Ввод - вывод низкого уровня], содержит информацию относительно операций ввода - вывода с описателями файла. Описатели файла - механизм низшего уровня, специфический для UNIX семейства операционных систем.
  • Глава 9 [Интерфейс файловой системы], имеет описания операций на всех файлах, например функций для их удаления и переименования и для создания новых каталогов. Эта глава также содержит информацию, относительно того, как Вы можете обращаться к атрибутам файла, например к режимам защиты файла.
  • Глава 10 [Каналы и FIFO (первый зашел - первый вышел)], содержит информацию относительно простых межпроцессорных механизмов связи. Каналы обеспечивают связь между двумя связанными процессами (типа "родитель-порожденнным"), в то время как FIFO обеспечиваю связь между процессами, совместно используя общую файловую систему.
  • Глава 11 [Гнеза], описывает более сложный межпроцессорный механизм связи, который позволяет процессам, выполняющимся на различных машинах, связаться через сетью. Эта глава также содержит информацию относительно Межсетевой адресации главной ЭВМ и как использовать базы данных сетей системы.
  • Глава 12 [Интерфейс терминала низкого уровня], описывает, как Вы можете изменять атрибуты устройства терминала. Например, если Вы хотите отключать отображение символов, печатаемых пользователем, читайте эту главу.
  • Глава 13 [Математика], содержит информацию относительно математических библиотечных функций. Они включают такие вещи как генераторы случайных чисел и функции остатка, а также обычные тригонометрические и показательные функции на числах с плавающей запятой.
  • Глава 14 [Функции арифметики низкого уровня], описывают функции для простой арифметики, анализ чисел с плавающей запятой, и чтения чисел из строк.
  • Глава 15 [Поиск и сортировка], содержит информацию относительно функций для поиска и сортировки массивов. Вы можете использовать эти функции для любого вида массива, обеспечивая соответствующую функцию сравнения.
  • Глава 16 [Сопоставление с образцом], функции для определения соответствия регулярных выражений и образцов имени файла оболочки, и для расширяющихся слов, как делает оболочка.
  • Глава 17 [Дата и время], описывает функции для измерения календарного времени и процессорного времени, также как функции для установки будильников и таймеров.
  • Глава 18 [Расширения символов], содержит информацию относительно управления символами, и строками, используя набор символов больший чем, представлен в обычном типе данных char.
  • Глава 19 [Положение], описывает как выбор специфической страны или языка воздействует на поведение библиотеки. Например, эффекты положения воздействуют на последовательности объединений для строк и на то как форматируются валютные значки.
  • Глава 20 [Нелокальные выходы], содержит описания функций setjmp и longjmp. Эти функции обеспечивают средства для goto-подобных переходов, возможно из одной функции в другую.
  • Глава 21 [Обработка сигнала], сообщает Вам все относительно сигналов, что это такое, как установить драйвер, который вызывается, когда специфический вид сигнала поставлен, и как предотвратить сигналы во время выполнения критических разделов вашей программы.
  • Глава 22 [Запуск процесса], сообщает, как ваши программы могут обращаться к их параметрам командной строки и системным переменным.
  • Глава 23 [Порожденнные процессы], содержит информацию относительно того, как начать новые процессы и выполнять программы.
  • Глава 24 [Управление заданиями], описывает функции для управления группами процесса. Этот материал, вероятно, представляет интерес только, если Вы пишете оболочку.
  • Раздел 25.12 [База данных пользователей], и раздел 25.13 [База данных групп], сообщают Вам, как обратиться к базам данных групп и пользователей системы.
  • Глава 26 [Информация системы], описывает функции для получения информации относительно аппаратных средств и конфигурации программного обеспечения,когда выполняется ваша программа.
  • Глава 27 [Конфигурация системы], сообщает Вам, как Вы можете получить информацию относительно различных ограничений операционной системы. Большинство этих параметров предусмотрено для совместимости с POSIX.
  • Приложение A [Особенности языка], содержит информацию относительно библиотечной поддержки для стандартных частей C языка, включая такие вещи как оператор sizeof или символическая постоянная NULL, форма записи функций, принимающих переменное числа параметров, и констант, описывающих диапазоны и другие свойства числовых типов. Имеется также простой механизм отладки, который разрешает поместить утверждения в ваш код, и напечатать диагностические сообщения, если тесты не прошли.
  • Приложение B [Обзор библиотеки], дает обзор всех функций, переменных, и макрокоманд в библиотеке, с полными типами данных и функциональными прототипами, и говорит, от какого стандарта или системы каждая происходит.
  • Приложение C [Сопровождение], объясняет, как формировать и установить GNU C библиотеку на вашей системе, куда сообщать о всех ошибках, которые Вы можете найти, и как добавить новые функции или перенести библиотеку на новоую систему.

Если Вы уже знаете имя средства, которое Вас интересует, Вы можете найти его в Приложении B [Обзор библиотеки]. Оно даст Вам обзор синтаксиса и указатель, по которому Вы можете найти более детализированное описание. Это приложение особенно полезно, если Вы хотите только проверить порядок и тип параметров функции. Оно также сообщает Вам, от какого стандарта или системы происходит каждая функция, переменная, или макрокоманда.

2. Сообщения об ошибках

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

Эта глава описывает, как работают средства сообщений об ошибках. Чтобы использовать эти средства, ваша программа должна включить заголовочный файл "errno.h".

2.1 Проверка Ошибок

Большинство библиотечных функций возвращает специальное значение, чтобы указать, что они потерпели неудачу. Специальное значение типично ­ 1, нулевой указатель, или константа типа EOF, которая определена для той цели. Но это значение возврата сообщает Вам только то, что ошибка произошла. Чтобы выяснять что это было, Вы должны рассмотреть код ошибки, сохраненный в переменной errno. Эта переменная объявлена в заголовочном файле "errno.h".

Переменная errno содержит номер ошибки системы. Вы можете изменять значение errno.

С тех пор как errno объявлена изменяемой, она может быть асинхронно изменена драйвером сигнала; см. раздел 21.4 [Определение драйверов]. Однако, правильно написанный драйвер сигнала сохраняет и восстанавливает значение errno, так что Вы вообще не должны волноваться относительно этой возможности, разве что при нааписании драйверов сигнала.

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

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

Примечание относительно переносимоси: ANSI C определяет errno скорее как "модифицируемое именуемое выражение", чем как переменную, разрешая ему выполняться как макрокоманде. Например, его расширение может включать обращение к функции, подобно * _errno (). Фактически, это встроено систему GNU непосредственно. GNU библиотека, на не-GNU системах, делает то, что правильно для этой специфической системы.

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

Все коды ошибки имеют символические имена; т. е. это макрокоманды, определенные в "errno.h". Имена начинаются с "E" и символа верхнего регистра или цифры; Вы должны рассмотривать имена такой формы, как зарезервированные имена. См. раздел 1.3.3 [Зарезервированные имена].

Значения кода ошибки - это различные положительные целые числа, с одним исключением: EWOULDBLOCK и EAGAIN - имеют одинаковый код. Так как значения отличны, Вы можете использовать их как метки в утверждении выбора; только не используйте, и EWOULDBLOCK и EAGAIN. Ваша программа не должна иметь никаких сомнений относительно специфических значений этих символических констант.

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

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

2.2 Коды ошибок

Макрокоманды кода ошибки определены в заголовочном файле "errno.h". Каждая из них преобразуется в константное целое значение. Некоторые из этих ошибок не могут произойти в системе GNU, но они могут происходить при использовании библиотеки GNU в других системах.

int EPERM (макрос)

Не разрешенная операция; только владелец файла (или другого обьекта) или процессы со специальными привилегиями могут выполнять эту операцию.

int ENOENT (макрос)

Нет такого файла или каталога. Это - ошибка типа "файл не существует" для обычных файлов, которые вызваны в контекстах, где они, как ожидается, уже существуют.

int ESRCH (макрос)

Нет процесса соответствующего заданному.

int EINTR (макрос)

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

Вы можете выбрать показ резюме функций после сигнала EINTR; см. раздел 21.5 [Прерванные Примитивы] .

int EIO (макрос)

Ошибка ввода-вывода, обычно используется для ошибок физического чтения или записи.

int ENXIO (макрос)

Нет такого устройства или адреса. Система попробовала использовать устройство, указанное файлом, который Вы определили, и не смогло найти это устройство. Это может означать, что файл устройства был установлен неправильно, или физическое устройство отсутствует или не правильно присоединено к компьютеру.

int E2BIG (макрос)

Список параметров слишком длинный; используется, когда параметры, переданные одной из функций (см. раздел 23.5 [Выполнение файла] ) занимают слишком много пространства памяти. Это условие никогда не возникает в системе GNU.

int ENOEXEC (макрос)

Недопустимый формат исполняемого файла. Это условие обнарживается запускаемыми функциями; см. раздел 23.5 [Выполнение файла].

int EBADF (макрос)

Плохой описатель файла; например, ввод - вывод на описателе, который был закрыт или чтение из описателя, открытого только для записи (или наоборот).

int ECHILD (макрос)

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

int EDEADLK (макрос)

Тупик; распределение ресурсов системы оценено как ситуация тупика. Система не гарантирует, что она будет обращать внимание на все такие ситуации. Эта ошибка означает, что Вам повезло; система могла зависнуть. См. раздел 8.11 [Блокировки файла].

int ENOMEM (макрос)

Нет доступной памяти. Система не может распределять виртуальную память, потому она полна.

int EACCES (макрос)

Отклоненное право; права файла не позволяют предпринятую операцию.

int EFAULT (макрос)

Плохой адрес; был обнаружен недопустимый указатель.

int ENOTBLK (макрос)

Не специальный файл, был дан в ситуации, которая требует блок файов. Например, при попытке установить обычный файл как файловую систему в UNIX дает эту ошибку.

int EBUSY (макрос)

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

int EEXIST (макрос)

Файл существует; существующий файл был определен в контексте, где имеет смысл определять только новый файл.

int EXDEV (макрос)

Была обнаружена попытка, сделать неподходящую компоновку файловой системы. Это случается не только, когда Вы используете связи (см. раздел 9.3 [Сложные связи]) но также, когда Вы переименовываете файл (см. раздел 9.6 [Переименование файлов]).

int ENODEV (макрос)

Функции, которая ожидает специфический тип устройства, был дан неправильный тип устройства.

int ENOTDIR (макрос)

Был определен файл, а не каталог, когда требуется каталог.

int EISDIR (макрос)

Указан каталог; попытка открыть каталог для записи дает эту ошибку.

int EINVAL (макрос)

Недопустимый параметр. Используется, чтобы указать различные виды проблем с указанием неправильного параметра для библиотечной функции.

int EMFILE (макрос)

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

int ENFILE (макрос)

Имеется слишком много различных открытых экземпляров файла во всей системе. Обратите внимание, что любое число связанных каналов считается только одним открытым экземпляром файла; см. раздел 8.5.1 [Связанные каналы]. Эта ошибка никогда не происходит в системе GNU.

int ENOTTY (макрос)

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

int ETXTBSY (макрос)

Попытка выполнить файл, который является в настоящее время открытым для записи, или записи в файл который в настоящее время выполняется. Это не является ошибкой в системе GNU; текст по мере необходимости копируется.

int EFBIG (макрос)

Файл слишком большой; размер файла больше чем позволено системой.

int ENOSPC (макрос)

Нет места на устройстве; операция записи в файл потерпела неудачу, потому что диск полон.

int ESPIPE (макрос)

Недопустимая операция установки.

int EROFS (макрос)

Была сделана попытка изменить что - нибудь в файловой системе только для чтения.

int EMLINK (макрос)

Слишком много связей; число связей одиночного файла слишком велико. Переименование может вызывать эту ошибку, если переименовываемый файл уже имеет максимальное число связей (см. раздел 9.6 [Переименование файлов]).

int EPIPE (макрос)

Разрушенный канал; не имеется процесса читающего с другого конца канала. Каждая библиотечная функция, которая возвращает этот код ошибки также генерирует сигнал SIGPIPE; если этот сигнал не обработан или не блокирован, то он завершает программу . Таким образом, ваша программа фактически не будет никогда видеть EPIPE, если она не обработала или не блокировала SIGPIPE.

int EDOM (макрос)

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

int ERANGE (макрос)

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

int EAGAIN (макрос)

Ресурс временно недоступен; обращение может работать, если Вы пробуете позже.

int EWOULDBLOCK (макрос)

Операция, которая бы была блокировала предпринята на объекте, который имеет выбранный режим не-блокирования.

Примечание относительно переносимости: В 4.4BSD и GNU, EWOULDBLOCK и EAGAIN - совпадают. Более ранние версии BSD (см. раздел 1.2.3 [Berkeley UNIX]) имеют два различных кода, и используют EWOULDBLOCK, чтобы указать операцию ввода-вывода, которая блокировала бы объект с набором режимов неблокирования, а EAGAIN для других видов ошибок.

int EINPROGRESS (макрос)

Операция, которая не может завершаться немедленно, была инициализирована в объекте, который имеет выбранный режим неблокирования. Некоторые функции, которые должны всегда блокировать (типа, connect ; см., раздел 11.8.1 [Соединение] ) никогда не возвращает EWOULDBLOCK. Взамен, они возвращают EINPROGRESS, чтобы указать, что операция начата и займет некоторое время. Попытайтесь управлять объектом прежде, чем обращение завершится возвратив EALREADY.

int EALREADY (макрос)

Операция уже выполняется в объекте, который имеет выбранный режим неблокирования.

int ENOTSOCK (макрос)

Был определен файл,а не гнездо, когда требуется гнездо.

int EDESTADDRREQ (макрос)

Нет был обеспечен адрес адресата для операции гнезда.

int EMSGSIZE (макрос)

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

int EPROTOTYPE (макрос)

Тип гнезда не поддерживает запрашиваемый протокол связи.

int ENOPROTOOPT (макрос)

Вы определили опцию гнезда, которая не имеет смысла для специфического протокола, используемого гнездом. См. раздел 11.11 [Опции гнезда].

int EPROTONOSUPPORT (макрос)

Область гнезда не поддерживает запрашиваемый протокол связи (возможно, потому что запрашиваемый протокол полностью недопустим.) См. раздел 11.7.1 [Создание гнезда].

int ESOCKTNOSUPPORT (макрос)

Тип гнезда не установлен.

int EOPNOTSUPP (макрос)

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

int EPFNOSUPPORT (макрос)

Семейство протоколов связи гнезда, которое Вы запросили, не обеспечивается.

int EAFNOSUPPORT (макрос)

Семейство адресов, заданное для гнезда несогласованно с протоколом, используемым на гнезде. См. Главу 11 [Гнезда].

int EADDRINUSE (макрос)

Запрашиваемый адрес гнезда - уже используется. См. раздел 11.3 [Адреса гнезда].

int EADDRNOTAVAIL (макрос)

Запрашиваемый адрес гнезда не доступен; например, Вы попробовали дать гнезду имя, которое не соответствует местному главному имени. См. раздел 11.3 [Адрес Гнезда].

int ENETDOWN (макрос)

Операция с гнездом потерпела неудачу, потому что нет сети.

int ENETUNREACH (макрос)

Операция гнезда потерпела неудачу, потому что подсеть, содержащая главную ЭВМ была недоступна.

int ENETRESET (макрос)

Сетевое соединение было сброшено, потому что отдаленная главная ЭВМ умерла.

int ECONNABORTED (макрос)

Сетевое соединение было прервано локально.

int ECONNRESET (макрос)

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

int ENOBUFS (макрос)

Буфера ядра для операций ввода - вывода занят весь.

int EISCONN (макрос)

Вы пытаетесь соединить гнездо, которое уже соединено. См. раздел 11.8.1 [Соединение].

int ENOTCONN (макрос)

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

int ESHUTDOWN (макрос)

Гнездо уже было закрыто.

int ETIMEDOUT (макрос)

Операция гнезда с заданной блокировкой по времени не получила никакого ответа в течение периода блокировки по времени.

int ECONNREFUSED (макрос)

Отдаленная главная ЭВМ отказала в сетевом соединении (обычно из-за того, что не запущено запрашиваемое обслуживание).

int ELOOP (макрос)

При поиске имени файла столкнулись со слишком многими уровнями символических связей. Часто это указывает на цикл символических связей.

int ENAMETOOLONG (макрос)

Имя файла слишком длинное (больше чем PATH_MAX; см. раздел 27.6 [Ограничения для файлов]) или главное имя слишком длинное (в gethostname или sethostname; см. раздел 26.1 [Главная идентификация]).

int EHOSTDOWN (макрос)

Отдаленная главная ЭВМ для запрашиваемого сетевого соединения не реагирует.

int EHOSTUNREACH (макрос)

Отдаленная главная ЭВМ для запрашиваемого сетевого соединения не доступна.

int ENOTEMPTY (макрос)

Каталог, не пустой, а ожидался пустой каталог. Обычно эта ошибка происходит, когда Вы пробуете удалять каталог.

int EUSERS (макрос)

Файловая система спутана, потому что имеется слишком много пользователей.

int EDQUOT

Пользовательское дисковое пространство превышено.

int ESTALE (макрос)

Просроченная NFS программа обработки файла. Это указывает на внутренний беспорядок в NFS системе, который появляется из-за перестановок файловой системы на главной ЭВМ станции. Восстановление этого условия обычно требует переустановки файловой системы NFS на местной главной ЭВМ.

int EREMOTE (макрос)

Была сделана попытка NFS-подсоединения удаленной файловой системой с именем файла, которое уже определяет установленный файл NFS. (Эта ошибка воникает на некоторых операционных системах, но мы думаем что это будет работать правильно на системе GNU, делающей этот код ошибки невозможным.)

int ENOLCK (макрос)

Нет доступной блокировки. Это используется средствами закрытия файла; см. раздел 8.11 [Блокировки файла]. Эта ошибка никогда не происходит в системе GNU.

int ENOSYS (макрос)

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

int EBACKGROUND (макрос)

В системе GNU, станции, обеспечивающие протокол терминала возвращают эту ошибку для некоторых операций, когда вызывающий оператор не входит в группу приоритетного процесса терминала. Пользователи обычно не видят эту ошибку, потому что функции типа чтения и записи транслируют ее в SIGTTIN или SIGTTOU сигнал. См. Главу 24 [Управление заданиями], для уточнения информации относительно групп процессов и этих сигналов.

int ED(макрос)

Опытный пользователь будет знать, что неправильно.

int EGREGIOUS (макрос)

Что Вы делаете?!!!

int EIEIO (макрос)

Идите домой и выпейте стакан теплого молока.

int EGRATUITOUS (макрос)

Этот код ошибки не имеет никакой цели.

2.3 Сообщения об ошибках

Библиотека имеет функции и переменные, разработанные, чтобы облегчить для вашей программы вывод информативных сообщений об ошибках в обычном формате. Функции strerror и perror дают Вам стандартное сообщение об ошибках для данного кода ошибки; переменная program_invocation_short_name дает Вам удобный доступ к имени программы, которая столкнулась с ошибкой.

      сhar * strerror ( int errnum) (функция)

функция strerror отображает код ошибки (см. раздел 2.1 [Прверка Ошибок]) заданный параметром errnum в описательную строку сообщения об ошибках. Значение возврата - указатель на эту строку.

Значение errnum обычно исходит из переменной errno.

Вы не должны изменять строку, возвращаемую strerror. Также, если Вы делаете последующие обращения к strerror, новая строка могла быть записана поверх старой. (Но гарантируется, что никакая библиотечная функция не вызовет strerror за вашей спиной.) Функция strerror объявлена в "string.h".

      void perror (const char * message) (функция)

Эта функция печатает сообщение об ошибках в поток stderr; см. раздел 7.2 [Стандартные Потоки].

Если Вы вызываете perror с сообщением, которое является или нулевым указателем или пустой строкой, perror печатает сообщение об ошибках, соответствуя errno, добавляя конечный символ перевода строки.

Если Вы обеспечиваете не-нулевой параметр сообщения, то perror начинает вывод с этой строки. Она добавляет двоеточие и пробел, чтобы отделить сообщение от строки ошибки, соответствующей errno.

Функция perror объявлена в "stdio.h".

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

Примечание относительно совместимости: функция strerror - новая особенность ANSI C, многие более старые C системы не поддерживают эту функцию.

Множество программ, которые не читают ввод с терминала, разработаны, чтобы выйти, если любой системный вызов терпит неудачу. В соответствии c соглашением, сообщение об ошибках из такой программы должно начаться с имени программы. Вы можете найти это имя в переменной program_invocation_short_name; полное имя файла сохранено в переменной program_invocation_name:

      сhar * program_invocation_name (переменная)

Значение этой переменной - имя, которое использовалось, чтобы вызвать программу, выполняющуюся в текущем процессе. Аналогично argv [0]. Обратите внимание, что это не обязательно какое-то полезное имя файла; часто она не содержит никаких имен. См. раздел 22.1 [Аргументы программы].

      сhar * program_invocation_short_name (переменная)

Значение этой переменной - имя, которое использовалось, чтобы вызвать программу, выполняющуюся в текущем процессе, без имен каталогов. (То есть то-же что и в program_invocation_name минус все до последней наклонной черты вправо, если что-то есть в наличии.)

Библиотечные код инициализации устанавливает обе из этих переменных перед вызовом main.

Примечание относительно переносимости: Эти две переменные ­ расширения GNU. Если Вы хотите, чтобы ваша программа работала с библиотеками, не относящимися к GNU, Вы должны сохранить значение argv [0] в main (основной программе), и удалить имена каталогов самостоятельно. Мы добавили эти расширения, чтобы сделать возможной написание замкнутых сообщений об ошибках подпрограммы, которые не требуют никакого явного сотрудничества с основной программой.

Имеется пример, показывающий, как обработать отказ открывать файл. Функция open_ sesame пробует открывать указанный файл для чтения и возвращает поток. Библиотечная функция fopen возвращает нулевой указатель, если она не может открыть файл по некоторым причинам. В той ситуации, open_sesame создает соответствующее сообщение об ошибках, используя функцию strerror, и завершает программу. Если мы хотим сделать другие вызовы из библиотек перед передачей кода ошибки к strerror, мы должны сохранить его в местной переменной, потому что те другие библиотечные функции могут записывать поверх errno.

       #include 
       #include 
       #include < stdlib.h >
       #include 
       FILE * open_sesame (char *name)
        {
          FILE *stream;
          errno = 0;
          stream = fopen (name, "r");
          if (stream == NULL)
           {
             fprintf (stderr, "%s: Couldn't open file %s; %s\n",
               program_invocation_short_name, name, strerror (errno));
             exit (EXIT_FAILURE);
           }
         else return stream;
       }

3. Распределение памяти


Система GNU обеспечивает несколько методов для распределения пространства памяти при явном управлении программы. Они различны по общности и по эффективности.
  • malloc производит общее динамическое распределение. См. раздел 3.3 [Беспрепятственное распределение].
  • оbstacks - другое средство, менее общее чем malloc, но более эффективное и удобное для стеко-подобного распределения. См. раздел 3.4 [Obstacks].
  • Функция alloca позволяет Вам динамически распределять память, которая будет освобождена автоматически. См. раздел 3.5 [Размер автоматической переменной].

                    

3.1 Концепции динамического распределения памяти

 
Динамическое распределение памяти - методика, в которой программы определяют, где сохранить некоторую информацию. Вы нуждаетесь в динамическом распределении, когда число блоков памяти, в которых Вы нуждаетесь, или то, как долго Вы продолжаете нуждаться в них, зависит от данных, с которыми Вы продолжаете работать.
Например, Вы можете нуждаться в блоке, чтобы сохранить строку прочитанную из входного файла; так как не имеется никаких ограничений, как долго нужно будет хранить строку, Вы должны динамически распределить память и динамически ее увеличивать, поскольку Вы читаете большее количество строк.
Или, Вам может понадобиться блок для каждой записи или каждого определения во входных сведениях; так как Вы не можете знать заранее, сколько их будет, Вы должны определять новый блок для каждой записи или определения, поскольку Вы их читаете.
Когда Вы используете динамическое распределение, распределение блока памяти представляет собой действие, которое программа запрашивает явно. Когда Вы хотите зарезервировать место, Вы вызываете функцию или макрокоманду и определяете размер аргументом. Если Вы хотите освободить место, Вы вызываете другую функцию или макрокоманду. Вы можете делать это всякий раз, когда Вы хотите, и так часто, как Вы хотите.

3.2 Динамическое Распределение в C

 
Язык С поддерживает два вида распределения памяти через переменные в программах C:
  • Статическое распределение - то, что случается, когда Вы объявляете статическую переменную. Каждая статическая переменная определяет один блок места, фиксированного размера. Место размещено один раз, когда ваша программа начата, и никогда не освобождается.
  • Автоматическое распределение происходит, когда Вы объявляете динамическую локальную переменную, например аргумент функции или местную переменную. Пространство для динамической локальной переменной резервируется, когда начинается выполнение составного утверждения, содержащего объявление, и освобождается, когда это составное утверждение, покидается.
В GNU C, длина автоматической памяти может быть выражением, которое изменяется. В других C реализациях, это должна быть константа. 
Динамическое распределение не обеспечивается C переменными; не имеется никакого класса памяти "dynamic", и не может быть переменной C, чье значение сохранено в динамически размещенном месте. Единственный способ обратиться к динамически размещенному месту - через указатель. Т.к. это менее удобно, и фактический процесс динамического распределения требует большего количества компьютерного времени, программисты использует динамическое распределение только когда ни статическое ни автоматическое распределение применить невозможно.
Например, если Вы хотите зарезервировать динамически некоторое место, чтобы разместить struct foobar, Вы не можете объявлять переменную типа struct foobar, чье содержание - динамически размещенное место. Но Вы можете объявить переменную struct foobar * типа указатель и назначить ей адрес. Тогда Вы можете использовать операторы "*" и "->" для этой переменной- указателя, чтобы обратиться по адресу:
      {
       struct foobar *ptr= (struct foobar *) malloc (sizeof (struct foobar));
       ptr->name = x;
       ptr->next = current_foobar;
       current_foobar = ptr;
       }

                    

3.3 Беспрепятственное распределение


Наиболее общее динамическое средство распределения - malloc. Оно разрешает Вам зарезервировать блоки памяти любого размера в любое время, увеличивать или уменьшать их, и освободждать блоки индивидуально в любое время (или не освобождать) .

Базисное распределение памяти


Чтобы зарезервировать блок памяти, вызовите malloc. Прототип для этой функции находится в "stdlib.h".
      void * malloc (size _t size) (функция)
Эта функция возвращает указатель к только что размещенныому блоку size байтов длиной, или нулевому указателю если блок не мог бы быть размещен. 
Содержание блока неопределено; Вы должны инициализировать его непосредственно (или использовать calloc; см. раздел 3.3.5 [Распределение очищенного места] ). Обычно Вы приводите значение указателя к виду объекта, который Вы хотите сохранять в блоке. Здесь мы показываем такой пример, и инициализации место нулями, используя библиотечную функцию memset (см. раздел 5.4 [Копирование и конкатенация]):
      struct foo *ptr;
      . . .
      ptr = (struct foo *) malloc (sizeof (struct foo));
      if (ptr == 0) abort ();
      memset (ptr, 0, sizeof (struct foo));
Вы можете сохранять результат malloc в любую переменную-указатель без приведения, потому что ANSI C автоматически преобразовывает void* в другой тип указателя когда необходимо. Но приведение необходимо в контекстах отличных от операторов назначения или если Вы хотите, чтобы ваш код выполнился в традиционном C. 
Не забудьте, что при распределении пространства для строки, аргумент malloc должен быть один плюс длина строки. Это - потому что строка завершена символом \0, который не учтен в "длине" строки, но нуждается в месте. Например:
      char *ptr;
      . . .
      ptr = (char *) malloc (length + 1);

                    

Примеры malloc


Если место не доступно, malloc возвращает нулевой указатель. Вы должны проверить значение каждого обращения к malloc. Полезно написать подпрограмму, которая вызывает malloc и сообщает ошибку, если значение ­ нулевой указатель, и возвращает результат только если значение отлично от нуля. Эта функция традиционно называется xmalloc:
      void * xmalloc (size_t size)
      {
       register void *value = malloc (size);
       if (value == 0) fatal ("virtual memory exhausted");
       return value;
      }
Это реальный пример использования malloc (через xmalloc). Функция savestring будет копировать последовательность символов в завершенную пустым указателем строку: 
      char * savestring (const char *ptr, size_t len)
      {
       register char *value = (char *) xmalloc (len + 1);
       memcpy (value, ptr, len);
       value[len] = '\0';
       return value;
      }
Блок, который malloc дает Вам, уже выровнен и может содержать любой тип данных. В системе GNU, адрес всегда делится на восемь; если размер блока - 16 или больше, то адрес всегда делится на 16. Более высокая граница (типа границы страницы) необходима гораздо реже; для этих случаев, используйте memalign или valloc (см. раздел 3.3.7 [Выравниваемые блоки памяти]). 
Обратите внимание, что память, размещенная после конца блока, вероятно будет в использовании для чего - нибудь еще; возможно для блока, уже размещенный другим обращением к malloc. Если Вы пытаетесь обрабатывать блок как дольше чем Вы установили, Вы можете разрушить данные, что malloc использует, чтобы следить за блоками, или Вы можете разрушить содержимое другого блока. Если Вы уже зарезервировали блок и обнаруживаете, что Вам нужен больший, используйте перераспределение (см. раздел 3.3.4 [Изменение размеров блока]).

Освобождение памяти, размещенной malloc


Когда Вы больше не нуждаетесь в блоке, который Вы создали malloc, используйте функцию free чтобы сделать блок доступным, для следующего резервировния. Прототип для этой функции находится в "stdlib.h".
      void free (void * ptr) (функция)
Функция освобождает блок памяти, указанной в ptr. 
      void cfree (void * ptr) (функция)
Эта функция делает то же самое что и предыдущая. Она предусматривает совместимость снизу вверх с SunOS. 
Освобождение блока изменяет содержание блока. Не ищите какие-либо данные (типа указателя на следующий блок в цепочке блоков) в блоке после его освобождения. Копируйте все необхоимое во вне блока перед его освобождением! Вот пример соответствующего способа освободить все блоки в цепочке, и строки на которые они указывают:
      struct chain {struct chain *next; char *name;}
      void free_chain (struct chain *chain)
      {
       while (chain != 0)
        {
         struct chain *next = chain->next;
         free (chain->name);
         free (chain);
         chain = next;
        }
      }
Иногда, free может фактически возвращать память в операционную систему и делать процесс меньшим. Обычно, все это позволяет, вызывая позже malloc, многократно использовать место. Тем временем, место остается в вашей программе в списе свободных, и используется внутри malloc. 
В конце программы, не имеется никаких указателей на освобожденые блоки, потому что все место программы было отдано обратно системе, когда процесс завершвлся.

Изменение размера блока


Часто Вы не уверены, насколько большой блок Вам будетнужен в конечном счете. Например, блок может быть буфером, что Вы используете, чтобы содержать строку читаемую из файла; неважно какой длины Вы делаете буфер первоначально, Вы можете сталкнуться со строкой, которая будет длиннее.
Вы можете делать блок длиннее, вызывая realloc. Эта функция объявлена в "stdlib.h".
      void * realloc (void * ptr, size _t newsize) (функция)
Функция realloc изменяет размер блока с адресом ptr, на newsize. 
Если место после конеца блока используется, realloc скопизует блок по новому адресу, где доступно большее количество свободного пространства. Значение realloc - новый адрес блока. Если блок должен передвигаться, realloc, копирует старое содержимое.
Если Вы передаете пустой указатель для ptr, realloc, ведет себя точно так же как "malloc (newsize)". Это может быть удобно, но остерегайтесь более старых реализаций (до ANSI C) которые не имеют права поддерживать это поведение, и будут вероятно что-то разрушать , когда realloc получит пустой указатель.
Подобно malloc, realloc может возвращать пустой указатель, если никакое пространство памяти не доступно, чтобы увеличить блок. Когда это случается, первоначальный блок остается нетронутым; он не изменяется и не перемещается.
В большинстве случаев это не имеет значения, что случается с первоначальным блоком, когда realloc терпит неудачу, потому что прикладная программа не может продолжаться, когда не хватает памяти, и единственное что, нужно сделать - это выдать сообщение о фатальной ошибке. Часто бывает удобно написать и использовать подпрограмму, традиционно называемую xrealloc, которая заботится о сообщениях об ошибках, как xmalloc делает для malloc:
      void * xrealloc (void *ptr, size_t size)
      {
       register void *value = realloc (ptr, size);
       if (value == 0) fatal ("Virtual memory exhausted");
        return value;
      }
Вы можете также использовать realloc, чтобы уменьшить блок. Чтобы не связывать много пространства памяти, когда необходимо немного. Создание меньшего блока иногда требует копировать его, так что это может неудаться, если никакое другое место не доступно. 
Если новый размер, который Вы определяете - такой же как старый, realloc, не изменит ничего и возвратит тот же самый адрес, который Вы дали.

Распределение очищенного места


Функция calloc резервирует память и обнуляет ее. Она объявлена в "stdlib.h".
      void * calloc (size_t count, size _t eltsize) (функция)
Эта функция резервирует блок достаточно длинный, чтобы содержать вектор из count элементов, каждый размера eltsize. Содержимое очищается обнулением прежде чем calloc сделает возврат. 
Вы можете определять calloc следующим образом:
      void * calloc (size_t count, size_t eltsize)
      {
       size_t size = count * eltsize;
       void *value = malloc (size);
       if (value != 0) memset (value, 0, size);
       return value;
      }
Мы редко используем calloc сегодня, потому что она эквивалентна простой комбинации других средств, которые больее часто используются. Это историческое средство, которое устаревает. 

Обсуждение эффективности malloc


Чтобы лучше использовать malloc, нужно знать, что GNU версия malloc всегда назначает наименьший объем памяти в блоках, чьи размеры являются степенями двойки. Она хранит раздельные пулы для каждой степени двойки. И каждый занимает столько места сколько страница. Следовательно, если у Вас есть свободный выбор размера маленького блока, чтобы сделать malloc более эффективным, делайте его степенью двойки.
Если страница разбита для определенного размеа блока, она не может многократно использоваться для другого размера, если все блоки этого размера не освобождены. В многих программах маловероятно, что это случается. Таким образом, Вы можете иногда делать программы использующие память более эффективно, используя блоки того же самого размера для многих различных целей.
Когда Вы запрашиваете о блоках памяти рамера страницы или больших, malloc использует различную стратегию; она округляет сверху размер до нескольких размеров странцы, и может обьединять и разбивать блоки как необходимо.
Причина для двух cтратегий то, что важно зарезервировать и освободить маленькие блоки так быстро как возможно, но для большого блока быстродействие менее важно, так как программа обычно тратит больше времени используя его. Больших блоков обычно меньше. Следовательно, для больших блоков, имеет смысл использовать метод, который занимает большее количество времени, чтобы минимизировать потраченное впустую место.

Распределение выравниваемых блоков памяти


Адрес блока, возвращенного malloc или realloc в системе GNU ­ всегда делится на восемь. Если Вы нуждаетесь в блоке, чей адрес ­ делится на более высокой степень двойки чем этот, используйте memalign или valloc. Эти функции объявлены в "stdlib.h".
С библиотекой GNU, Вы можете использовать free, чтобы освободить блоки которые возвращают memalign и valloc. Это не работает в BSD, т. к. BSD не обеспечивает ни какого способа освободить такие блоки.
      void * memalign (size _t size, size _t boundary) (функция)
Функция memalign зарезервирует блок size байтов чей адрес - делится на boundary. Граница boundary должна быть степенью двойки! Функция memalign работает, вызывая malloc, чтобы зарезервировать несколько больший блок, и возвращает адрес внутри блока, который находится на заданной границе. 
      void * valloc (size _t size) (функция)
Подобна memalign с размером страницы заданным как значение второго аргумента: 
      void * valloc (size_t size)
      {
       return memalign (size, getpagesize ());
      }

                    

Проверка непротиворечивости кучи


Вы можете указать, чтобы malloc проверила непротиворечивость динамической памяти, используя функцию mcheck. Эта функция - расширение GNU, объявленное в "malloc.h".
      int mcheck (void (* abortfn) (void)) (функция)
Вызывая mcheck сообщает, чтобы malloc выполнил случайные проверки непротиворечивости. Они будут захватывать вещи типа письменного соглашения после конца блока, который был размещен malloc. 
аbortfn аргумент - это функция, которая вызвается, когда несогласованность найдена. Если Вы обеспечиваете пустой указатель, используется функция аварийного прекращения работы.
Слишком поздно начинать проверку, если Вы уже зарезервировали что-­ нибудь с помощью malloc. Так как mcheck в этом случае ничего не делает. Функция возвращает -1, если Вы вызываете ее слишком поздно, и 0 иначе (в случае успеха).
Самый простой способ вызывать mcheck вовремя состоит в том, чтобы использовать опцию "-lmcheck" когда Вы компонуете вашу программу; то Вы вообще не должны изменять вашу исходную программу.

Ловушки для резервирования памяти


GNU C библиотека позволяет Вам изменять поведение malloc, realloc, и free, определяя соответствующие функции ловушки. Вы можете использовать эти ловушки, чтобы отладить программы, которые используют динамическое резервирование памяти.
Переменные-ловушки объявлены в "malloc.h".
__realloc_hook (переменная)

Значение этой переменной - указатель на функцию, которe realloc использует всякий раз, когда вызывается. Вы должны определить эту функцию, как:

      void * function (void * ptr, size _t size)
__free_hook (переменная)

Значение этой переменной - указатель на функцию, которую free использует всякий раз, когда вызывается. Вы должны определить эту функцию, как:

      void function (void * ptr)
Вы должны удостовериться, что функция, которую Вы устанавливаете как ловушку для одной из этих функций, не вызывает заменяемую функцию рекурсивно без того, чтобы сначала восстановить старое значение ловушки! Иначе, ваша программа будет эастревать в бесконечной рекурсии.
Это пример показывает как правильно использовать __malloc_hook. Мы устанавливаем функцию, которая выводит информацию каждый раз когда вызывается malloc. 
      static void *(*old_malloc_hook) (size_t);
      static void * my_malloc_hook (size_t size)
      {
       void *result; __malloc_hook = old_malloc_hook;
       result = malloc (size);
       __malloc_hook = my_malloc_hook;
       printf ("malloc (%u) returns %p\n", (unsigned  int) size, result);
       return result;
      }
      main ()
      {
       ...
       old_malloc_hook = __malloc_hook;
       __malloc_hook = my_malloc_hook;
       ...
      }
Функция mcheck (см. раздел 3.3.8 [Непротиворечивость кучи]) в ходе своей работы устанавливает такие ловушки. 

Статистика резервирования памяти при помощи malloc


Вы можете получить информацию относительно динамического резервирования памяти, вызывая функцию mstats. Эта функция и связанный тип данных объявлены в "malloc.h"; они являются расширением GNU.
      struct mstats (тип данных)
Этот структурный тип используется, чтобы возвратить информацию относительно динамической программы распределения памяти. Она содержит следующие поля: 
      size_t bytes_total
Это - полный размер памяти, управляемой malloc, в байтах. 
      size_t chunks_used
Это - число используемых кусков. (Программа распределения памяти внутренне получает куски памяти из операционной системы, и преобразует их в такие, которые удовлетворяют индивидуальным запросам malloc; см. раздел 3.3.6 [Эффективность и malloc]) 
      size_t bytes_used
Это число используемых байтов. 
      size_t chunks_free
Это - число кусков, которые являются свободными - то есть которые были размещены операционной системой вашей программы, но теперь не используются. 
      size_t bytes_free
Это - число свободных байт. 
      struct mstats mstats (void) (функция)
Эта функция возвращает информацию относительно текущего динамического использования памяти в структуре типа struct mstats. 

Обзор функций, имеющих отношение к функции malloc


Это обзор функций, которые имеют отношение к malloc:
      void * malloc (size _t size)
Резервирует блок из size байт. См. раздел 3.3.1 [Базисное резервирование]. 
      void free (void *addr)
Освобождает блок, предварительно размещенный malloc. См. раздел 3.3.3 [Освобождение после malloc]. 
      void * realloc (void * addr, size _t size)
Делает блок, предварительно размещенный malloc больше или меньше, возможно, копируя его по новому расположению. См. раздел 3.3.4 [Изменение размеров блока]. 
      void * calloc (size _t count, size _t eltsize)
Резервирует блок в count * eltsize байт, используя malloc, и обнуляет содержимое. См. раздел 3.3.5 [Распределение очищенного места]. 
      void * valloc (size _t size)
Зарезервирует блок в size байт, начинающийся на границе страницы. См. раздел 3.3.7 [Выравниваемые блоки памяти]. 
      void * memalign (size _t size, size _t boundary)
Резервирует блок в size байт, начинающийся с адреса, который является делится на выравнивание. См. раздел 3.3.7 [Выравниваемые блоки памяти]. 
      int mcheck (void (* abortfn) (void))
Указывает, чтобы malloc выполнил случайную проверку непротиворечивости динамически размещенной памяти, и вызыватл abortfn, если найдена несогласованность. См. раздел 3.3.8 [Непротиворечивость кучи]. 
      void * (* __ malloc_hook) (size _t size)
Указатель на функцию, которую malloc использует всякий раз, когда вызывается. 
      void * (* __ realloc _hook) (void * ptr, size _t size)
Указатель на функцию, которую realloc использует всякий раз, когда вызывается. 
      void (* __ free _hook) (void * ptr)
Указатель на функцию, которую free использует всякий раз, когда вызывается. 
      struct mstats mstats (void)
Возвращают информацию относительно текущего динамического исполнения памяти. См. раздел 3.3.10 [Статистика malloc]. 

3.4 obstacks


obstack - пул памяти, содержащей стек объектов. Вы можете создавать любое число различных obstacks, и зарезервировать объекты в заданном obstacks. Внутри каждого obstack, последний размещенный объект должен всегда быть первым освобожденным, но различные obstacks независят от друг друга.
Кроме этого одного ограничения на порядок освобождения, obstacks полностью свободен: obstack может содержать любое число объектов любого размера. Они выполнены как макрокоманды, так что резервирование обычно очень быстро, так как объекты обычно маленькие. И единственные дополнительные непроизводительные затраты на объект необходимы, чтобы начать каждый объект с подходящей границы.

Создание obstacks


Утилиты для управления obstacks объявлены в заголовочном файле "obstack.h".
      struct obstack (тип данных)
obstack представляется структурой данных типа struct obstack. Эта структура имеет маленький фиксированный размер; она содержит состояния obstack и информацию о том, как как найти место, в котором размещены объекты. Она не содержит ни какой из объектов непосредственно. Вы не должны пробовать непосредственно обращаться к содержимому структуры; используйте только функции, описанные в этой главе. 
Вы можете объявлять переменные типа struct obstack и использовать их как obstacks, или Вы можете зарезервировать obstacks динамически подобно любому другому виду объекта. Динамическое резервирование obstacks разрешает вашей программе иметь переменное число различных стеков. (Вы можете даже зарезервировать структуру obstack в другом obstack, но это редко требуется.)
Все функции, которые работают с obstacks, требуют, чтобы Вы определили, какой obstack использовать. Вы делаете это указателем типа struct obstack *. Далее, мы часто будем говорить "obstack" когда, строго говоря, имеем в виду такой указатель.
Объекты в obstack упакованы в большие блоки называемые кусками. Структура struct obstack указывает на цепочку используемых в настоящее время кусков.
Библиотека obstack получает новый кусок всякий раз, когда Вы резервируете объект, которому не удовлетворяет предыдущий кусок. Так как библиотека obstack управляет кусками автоматически, Вы не должны уделять им много внимания, но Вы должны обеспечить функцию, которую библиотека obstack должна использовать, чтобы получить кусок. Обычно Вы обеспечиваете функцию, которая использует malloc непосредственно или косвенно. Вы должны также обеспечить функцию освобождения куска. Эти вопросы описаны в следующем разделе.

Подготовка к использованию obstacks


В каждый исходный файл, в котором Вы планируете использовать функции obstack, следует включить заголовочный файл "obstack.h":
      #include 
Также, если исходный файл использует макрокоманду obstack_init, он должен объявить или определить две функции или макрокоманды, которые будут вызываться библиотекой obstack. Это, obstack_chunk_alloc, которая используется, чтобы зарезервировать куски памяти, в которую объекты упакованы. Другая, obstack_chunk_free, которая используется, чтобы возвратить куски, когда объекты из них освобождены. 
Обычно они определены, чтобы использовать malloc через посредника xmalloc (см. раздел 3.3 [Беспрепятственное Резервирование]). Это выполнено следующей парой макроопределений:
      #define obstack_chunk_alloc xmalloc*

                    
      #define obstack_chunk_free free
Хотя память, которую Вы получаете используя obstacks действительно, исходит из malloc, использование obstacks - быстрее, потому что malloc вызывается менее часто, для больших блоков памяти. См. раздел 3.4.10 [Куски obstack], для полной информации. 
Во время выполнения, прежде, чем программа может использовать struct obstack object как obstack, она должна инициализировать obstack, вызывая obstack_init.
      void obstack_init (struct obstack * obstack_ptr) (функция)
Инициализирует obstack obstack_ptr для резервирования объектов. 
Имеются два примера того, как зарезервировать пространство для obstack и инициализировать его. Первый, obstack, который является статической переменной:
      static struct obstack myobstack;
      ...
      оbstack_init (&myobstack);
Во-вторых, obstack, который самостоятельно динамически размещен: 
      struct obstack * myobstack_ptr= (struct obstack *) xmalloc (sizeof(struct obstack));

      obstack_init (myobstack_ptr);

                    

Резервирование в obstack


Наиболее прямой способ зарезервировать объект в obstack - через obstack_alloc, которая вызывается почти как malloc.
      void * obstack_alloc (struct obstack * obstack_ptr, size _t size) (функция)
Резервирует неинициализированный блок size байт в obstack и возвращает адрес. Здесь obstack_ptr определяет, в каком obstack зарезервировать блок; это - адрес struct obstack object, который представляет obstack. Каждая функция obstack или макрокоманда требует, чтобы Вы определили obstack_ptr как первый аргумент. 
Например функция, которая резервирует копию строки str в определенном obstack, который находится в переменной string_obstack:
      struct obstack string_obstack;
      char * copystring (char *string)
      {
       char *s = (char *) obstack_alloc (&string_obstack, strlen (string) + 1);
       memcpy (s, string, strlen (string));
       return s;
      }
Чтобы зарезервировать блок с заданным содержимым, используйте функцию obstack_copy, объявляемую так: 
      void * obstack_copy (struct obstack * obstack_ptr, void *address, size_t size) (функция)
Резервирует блок и инициализирует его, копируя size байтов данных, начинающихся по адресеу 
      vоid * obstack_copy0 (struct obstack * obstack_ptr, void *address, size _t size) (функция)
Подобна obstack_copy, но конкатенирует дополнительный байт, содержащий пустой символ. Этот дополнительный байт не учтен в размере аргумента. 
Функция obstack_copy удобна для копирования последовательности символов в obstack как законченной пустым символом строки. Пример использования:
      char * obstack_savestring (char * addr, size _t size)
      {
       return obstack_copy (myobstack, addr, size);
      }
Сравните это с предыдущим примером сохранения строки, использующим malloc (см. раздел 3.3.1 [Базисное резервирование]). 

Освобождение объектов из obstack


Для освобждения объекта, размещенный в obstack, используйте функцию obstack_free. Так как obstack - стек объектов, освобождение одного объекта автоматически освобождает все другие объекты, зарезервированные позже в том же самом obstack.
      void obstack_free (struct obstack * obstack_ptr, void * object) (функция)
Если object - пустой указатель, все размещенные в obstack освобождаются. Если, object есть адрес объекта, размещенного в obstack, то объект освобождается, наряду с всеми размещенноми в obstack начиная с object. 
Обратите внимание, что, если object является пустым указателем, то результат - неинициализированный obstack. Для освобождения всей памяти в obstack, с возможным его использованием для дальнейшего резервирования, вызовите obstack_free с адресом первого объекта, размещенного в obstack:
      obstack_free (obstack_ptr, first_object_allocated_ptr);
Обратите внимание, что объекты в obstack сгруппированы в куски. Когда все объекты в куске становятся свободными, библиотека obstack автоматически освобождает кусок (см. раздел 3.4.2 [Подготовка obstack] ). Тогда другое obstack-, или не obstack-резервирование, может многократно использовать куска, занимаемое куском. 

Функции и макросы obstack


Интерфейсы для использования obstacks могут быть определены или как функции или как макрокоманды, в зависимости от транслятора. obstack средство работает со всеми C трансляторами, включая, и ANSI C и традиционный C, но имеются предосторожности, которые Вы должны соблюдать, если Вы планируете использовать трансляторы отличные от GNU C.
Если Вы используете традиционный не ANSI C транслятор, все obstack "функции" фактически определены только как макрокоманды. Вы можете вызывать эти макрокоманды подобно функциям, но Вы не можете использовать их любым другим способом (например, Вы не можете брать их адрес).
Вызов макрокоманд требует некоторых предосторожностей: а именно, первый операнд (указатель на obstack) не имеет права содержать никаких побочных эффектов, потому что он может быть вычислен больше чем один раз. Например, если Вы напишете: obstack_alloc (get_obstack (), 4), Вы увидите, что get_obstack может называться несколько раз. Если Вы используете * obstack_list_ptr ++ как аргумент-указатель obstack, Вы получите очень странные результаты, так как приращение может происходить несколько раз.
В ANSI C, каждая функция имеет, и макроопределение и определение функции. Определение функции используется, если Вы берете адрес функции без того, чтобы вызвать ее. Обычное обращение использует макроопределение по умолчанию, но Вы можете запрашивать определение функции, написав имя функции в круглых скобках, как показано здесь:
      char * x; void * (* funcp) (); /* Используем макрокоманду. */
      x = (char *) obstack_alloc (obptr, size);  /* Вызываем функцию. */
      x = (char *) (obstack_alloc) (obptr, size);  /* Берем адрес функции. */
      funcp = obstack_alloc;
Это - та же самая ситуация, что и в ANSI C для стандартных библиотечных функций. См. раздел 1.3.2 [Определение макросов]. 
Предупреждение: Когда Вы используете макрокоманды, Вы должны соблюдать предосторожности избавившись от побочных эффектов в первом операнде, даже в ANSI C.
Если Вы используете транслятор GNU C, эта предосторожность, необязательна, потому что различные расширения языка в GNU C разрешают определять макрокоманды, чтобы вычислять каждый аргумент только один раз.

Возрастающие объекты


Т.к. память в кусках obstack используется последовательно, возможно создать объект шаг за шагом, добавляя один или больше байт сразу к концу объекта. При таком способе, Вы не должны знать, сколько данных у Вас будет включено в объект до этого. Мы называем это методикой возрастастающих объектов. В этом разделе описаны специальные функции для добавления данных к возрастастающему объекту.
Вы не должны делать что-нибудь особенное, когда Вы начинаете наращивать объект. Использование одной из функций, чтобы добавить данные к объекту автоматически начинает его. Однако, необходимо явно указать, когда объект закончен. Это выполняется функцией obstack_finish.
Действительный адрес объекта, созданного таким образом не известен, пока объект не закончен. До тех пор, всегда остается возможность, что Вы добавите так много данных, что объект придется скопировать в новый кусок.
Поскольку obstack используется для возрастастающего объекта, Вы не можете использовать obstack для обычного резервирования другого объекта. Если, Вы попробуете это сделать, то место, уже добавленное к возрастастающему объекту, станет частью другого объекта.
      void obstack_blank (struct obstack * obstack_ptr, size _t size) (функция)
Базисной функцией для добавления к возрастастающему объекту является obstack_blank, которая добавляет место без его инициализированя. 
      void obstack_grow (struct obstack * obstack_ptr, void *data , size_t size) (функция)
Добавляет блок инициализированного места, используя obstack_grow, которая является аналогом obstack_copy для возрастающих объектов. Она добавляет size байт данных к возрастастающему объекту, копируя содержимое из данных. 
      void obstack_grow0 (struct obstack * obstack_ptr, void *data, size_t size) (функция)
Это - аналог obstack_copy для возрастающих объектов. Она добавляет size байт копируемых из данных, добавляя дополнительный пустой символо. 
      void obstack_1grow (struct obstack * obstack_ptr, char c) (функция)
Чтобы добавить только один символ, используется функция obstack_1grow. Она добавляет одиночный байт с к возрастастающему объекту. 
      void * obstack_finish (struct obstack * obstack_ptr) (функция)
Когда Вы закончили увеличивать объект, используйте функцию obstack_finish, чтобы закрыть его и получить конечный адрес. 
Если Вы закончили объект, obstack доступен для обычного резервирования или для увеличения другого объекта.
Когда Вы формируете объект, Вы будете вероятно должны знать, позже сколько места занял. Вы не должны следить за этим, потому что Вы можете выяснять длину из obstack перед самым окончанием объекта функцией obstack_object_size, объявленный следующим образом:
      size _t obstack_object_size (struct obstack * obstack_ptr) (функция)
Эта функция возвращает текущий размер возрастастающего объекта, в байтах. Не забудьте вызывать эту функцию перед окончанием объекта. После того, как он закончен, obstack_object_size будет возвращать нуль. 
Если Вы начали увеличивать объект и желаете отменить это, Вы должны закончить его и тогда освободить его, примерно так:
      obstack_free (obstack_ptr, obstack_finish (obstack_ptr));
Это не имеет никакого эффекта, если никакой объект не возрастастал. 
Вы можете использовать obstack_blank с отрицательным аргументом size, чтобы делать текущий объект меньше. Только не пробуйте сокращать его до меньше нуля, не имеется никаких сведенний, что случиться, если Вы сделаете это.

Сверхбыстро возрастастающие объекты


Обычные функции для возрастастающих объектов делают непроизводительные затраты для проверки, имеется ли участок памяти для нового роста в текущем куске. Если Вы часто создаете объекты в с маленькими шагами роста, эти непроизводительные затраты, могут быть значительны.
Вы можете уменьшать непроизводительные затраты, используя специальный "быстрый рост", т. е. функции, которые выращивают объект без проверки. Чтобы иметь здоровую программу, Вы должны делать проверку самостоятельно. Если Вы делаете это самым простым способом каждый раз. когда Вы собираетесь, добавлять данные к объекту, Вы ничего не приобретете, потому что это и делают обычные функции возрастания. Но если Вы можете проверить менее часто, или проверять более эффективно, то Вы сделаете программу быстрее.
Функция obstack_room возвращает количество памяти, доступной в текущем куске. Она объявлена следующим образом:
      size _t obstack_room (struct obstack * obstack_ptr) (функция)
Возвращает число байтов которые могут быть добавлены к текущему возрастастающему объекту (или к объекту, собирающемуся начаться) в obstack при использовании быстрых функций роста. 
Если Вы знаете, что имеется участок памяти, Вы можете использовать эти быстрые функции роста для добавления данных к возрастастающему объекту:
      void obstack_1grow_fast (struct obstack * obstack_ptr, char c) (функция)
Функция obstack_1grow_fast добавляет один байт, содержащий символ с к возрастастающему объекту в obstack obstack_ptr. 
      void obstack_blank_fast (struct obstack * obstack_ptr, size _t size) (функция)
Функция obstack_blank_fast добавляет size байтов к возрастастающему объекту в obstack obstack_ptr без их инициализации. 
Если Вы проверяете место, используя obstack_room и нет достаточного участка памяти, для того, что Вы хотите добавлять, то быстрые функции роста не безопасны. В этом случае, просто используйте соответствующую обычную функцию роста. Если она будет копировать объект в новый кусок; то будет иметься больше доступной памяти.
Так, каждый раз когда Вы используете обычную функцию роста, проверяйте есть ли достаточного места, используя obstack_room. Как только объект скопирован в новый кусок, будет снова иметься много места, так что программа будет начинать использовать быстрые функции роста.
Вот пример:
      void add_string (struct obstack * obstack, char * ptr, size _t len)
      {
       while  (len > 0)
       {
        if (obstack_room (obstack) > len)
         {          /* Мы имеем достаточный участок памяти: добавляйте все
                        быстро. */
           while (len - > 0) obstack_1grow_fast (obstack, * ptr ++);
         }
        else
         {
      /* Нет достаточного участка памяти. Добавьте один символ, он может
 быть скопирован в новый кусок для создания места. */
          obstack_1grow (obstack, * ptr ++); len -;
         }
       }
      }

                    

Состояние obstack


Имеются функции, которые обеспечивают информацию относительно текущего состояния резервирования в obstack. Вы можете использовать их, чтобы узнать относительно объекта при все еще возрастании это.
      void * obstack_base (struct obstack * obstack_ptr) (функция)
Эта функция возвращает временный адрес начала в настоящее время возрастастающего объекта в obstack_ptr. Если Вы заканчите объект немедленно, он будет иметь этот адрес. Если Вы сначала его увеличиваете, он может перерасти этот кусок и адрес будет изменяться! 
Если никакой объект в данный момент не возрастастает, это значение показывает, где будет начинаться следующий объект, который Вы зарезервируете.
      void * obstack_next_free (struct obstack * obstack_ptr) (функция)
Эта функция возвращает адрес первого свободного байта в текущем куске obstack obstack_ptr, т. е. - конца в настоящее время возрастастающего объекта. Если никакой объект не возрастастает, obstack_next_free, возвращает то же самое значение что и obstack_base. 
      size _t obstack_object_size (struct obstack * obstack_ptr) (функция)
Эта функция возвращает размер в байтах возрастастающего в настоящее время объекта. Она эквивалентна toobstack_next_free (obstack_ptr) ­ obstack_base (obstack_ptr) 

Выравнивание данных в obstacks


Каждый obstack имеет границу выравнивания; каждый объект, размещенный в obstack автоматически начинается на адресе, который делится на заданную границу (выравнивание). По умолчанию, эта граница ­ 4 байта.
Чтобы обращаться к границе выравнивания obstack, используйте макрокоманду obstack_alignment_mask, чей функциональлный прототип
      int obstack_alignment_mask (struct obstack * obstack_ptr) (макрос)
Его значение - битовая маска; установленная еденица, указывает, что соответствующий бит в адресе объекта должен быть 0. Значение маски должно быть на еденицу меньше чем степень 2; и все адреса объекта ­ делится на эту степень 2. По умолчанию значение маски - 3, чтобы адреса - делились на 4. Значение маски 0 означает, что объект может начинаться с любого целого адреса (то-есть никакое выравнивание не требуется). 
Расширение макрокоманды obstack_alignment_mask - именующее выражение, так что Вы можете изменять маску назначением. Например, это утверждение:
      obstack_alignment_mask (obstack_ptr) = 0;
Выключает обработку выравнивания в заданном obstack. 
Обратите внимание, что изменение в маске выравнивания не действует до окончания или размещения следующего объекта в obstack. Если Вы не увеличиваете объект, Вы может заставить новую маску выравнивания воздействовать немедленно, вызывая obstack_finish. Она заканчит объект нулевой длины и то сделает соответствующее выравнивание для следующего объекта.

Куски obstack


obstacks работает, резервируя пространство для себя в больших кусках, и разбивает место снаружи на куски, чтобы удовлетворить ваши запросы. Куски - обычно длиной 4096 байтов, если Вы не определите другой размер куска. Размер куска включает 8 байтов непроизводительных затрат, которые фактически не используются для сохранения объектов. Независимо от заданного размера, длинные объекты будут размещены в более длинные куски, когда необходимо.
obstack библиотека зервирует куски, вызывая функцию obstack_chunk_alloc, которую Вы должны определить. Когда кусок больше не нужен, если Вы освободили в нем все объекты, obstack библиотека освобождает кусок, вызывая obstack_chunk_free, которыую Вы должны также определить.
Эти две функции должны быть определены (как макрокоманды) или объявляться (как функции) в каждом исходном файле, который использует obstack_init (см. раздел 3.4.1 [Создание obstacks]). Наиболее часто они определены как макрокоманды подобно:
      #define obstack_chunk_alloc xmalloc
      #define obstack_chunk_free free
Обратите внимание, что это простые макрокоманды (никаких аргументов). Определения макросов с аргументами работать не будут! Необходимо чтобы obstack_chunk_alloc или obstack_chunk_free, расширялась в имя функции, если она не является именем функции. 
Функция, которая фактически осуществляет obstack_chunk_alloc, не может возвратить "отказ" в любом режиме, потому что obstack библиотека не подготовлена, чтобы обработать отказ. Следовательно, malloc непосредственно не подходит. Если функция не может получить место, она должна также завершить процесс (см. раздел 22.3 [Прерывание программ] или делать нелокальный выход, используя longjmp (см. Главу 20 [Нелокальные выходы] ).
Если Вы зарезервируете куски с malloc, размер куска, должен быть степенью 2. Заданный по умолчанию размер куска - 4096, был выбран, достаточно большим чобы удовлетворить много типичных запросов на obstack однако достаточно коротким, чтобы не тратить впустую слишком много памяти.
      size _t obstack_chunk_size (struct obstack * obstack_ptr) (макрос)
Он возвращает размер куска данного obstack. 
Так как эта макрокоманда расширяется до именующего выражения, Вы можете определить новый размер куска, назначая новое значение. Ее выполнение не подействует на куски, уже размещенные, но изменит размер кусков, размещенных в том конкретном obstack в будущем., вряд ли, будет полезно сделать размер куска меньше, но создание большего могло бы увеличивать эффективность, если Вы зарезервируете много объектов, чьи размеры являются сравнимыми с размером куска. Вот как это можно сделать:
      if (obstack_chunk_size (obstack_ptr) < new_chunk_size)
       obstack_chunk_size (obstack_ptr) = new_chunk_size;

                    

Обзор функций, имеющих отношение к obstack


Это обзор всех функций, связанных с obstack. Каждая берет в качестве первого аргумента адрес obstack (struct obstack *).
      void obstack_init (struct obstack * obstack'ptr)
Инициализирует использование obstack. См. раздел 3.4.1 [Создание obstacks]. 
      void * obstack_alloc (struct obstack * obstack'ptr, size_t size)
Резервирует объект как size неинициализированных байт. См. раздел 3.4.3 [Резервирование в obstack]. 
      void * obstack_copy (struct obstack * obstack'ptr, void *address, size_t size)
Резервирует объект из size байтов, с содержимым, скопированным из адреса address. См. раздел 3.4.3 [Резервирование в obstack]. 
      void * obstack_copy0 (struct obstack * obstack'ptr, void *address, size_t size)
Резервирует объект из size + 1 байт, size из которых скопированы из адреса address, сопровождаемый пустым символом в конце. См. раздел 3.4.3 [Резервирование в obstack]. 
      void obstack_free (struct obstack * obstack'ptr, void * object)
Освобождает обьект (и все размещенное в заданном obstack позже чем object). См. раздел 3.4.4 [Освобождение obstack объектов]. 
      void obstack_blank (struct obstack * obstack'ptr, size_t size)
Добавляет size неинициализированных байтов к возрастастающему обьекту object. См. раздел 3.4.6 [Возрастающие объекты]. 
      void obstack_grow (struct obstack * obstack'ptr, void * address,
 size _t size)
Добавляет size байт, скопированных из address, к возрастастающему обьекту object. См. раздел 3.4.6 [Возрастастающие объекты]. 
      void obstack_grow0 (struct obstack * obstack'ptr, void * address,
 size _t size)
Добавляет size байт, скопированных из address, к возрастастающему обьекту object, и еще добавляет другой байт, содержащий пустой символ. См. раздел 3.4.6 [Возрастастающие объекты]. 
      void obstack_1grow (struct obstack * obstack'ptr, char data'char)
Добавляет один байт данных к возрастастающему обьекту object. См. раздел 3.4.6 [Возрастастающие объекты]. 
      void * obstack_finish (struct obstack * obstack'ptr)
Завершает объект, который возрастастает и возвращает постоянный address. См. раздел 3.4.6 [Возрастающие объекты]. 
      size _t obstack_object_size (struct obstack * obstack'ptr)
Получает текущий размер в настоящее время возрастастающего объекта. См. раздел 3.4.6 [Возрастающие объекты]. 
      void obstack_blank_fast (struct obstack * obstack'ptr, size _t size)
Добавляет size неинициализированных байт к возрастастающему объекту без проверки, что имеется достаточный участок памяти. См. раздел 3.4.7 [Сверхбыстро возрастастающие объекты]. 
      vid obstack_1grow_fast (struct obstack * obstack'tr, char
 data'char)
Добавляет один байт к возрастастающему объекту без проверки, что имеется достаточный участок памяти. См. раздел 3.4.7 [Сверхбыстро возрастастающие объекты]. 
      size _t obstack_room (struct obstack * obstack'ptr)
Получает участок памяти, теперь доступный для возрастания текущего объекта. См. раздел 3.4.7 [Сверхбыстро возрастающие объекты]. 
      int obstack_alignment_mask (struct obstack * obstack'ptr)
Маска, используемая для выравнивания начала объекта. Это ­ именующее выражение (адрес переменной). См. раздел 3.4.9 [Выравнивание данных obstacks]. 
      size _t obstack_chunk_size (struct obstack * obstack'ptr)
Размер распределяемых кусков. Это - именующее выражение. См. раздел 3.4.10 [ Куски obstack]. 
      void * obstack_base (struct obstack * obstack'ptr)
Пробный начальный адрес в настоящее время возрастастающего объекта. См. раздел 3.4.8 [Состояние obstack]. 
      void * obstack_next_free (struct obstack * obstack'ptr)
Адрес следующий сразу за концом в настоящее время возрастастающего объекта. См. раздел 3.4.8 [Состояние obstack]. 

3.5 Автоматическая память с учетом размера переменной


Функция alloca поддерживает вид полудинамического резервирования, в котором блоки размещены динамически, но освобождаются автоматически.
Распределение блока alloca - явное действие; Вы можете зарезервировать так много блоков, как Вы желаете, и вычислять размеры во время выполнения. Но все блоки освобождатся, когда Вы выходите из функции из которой alloca вызывалась,как если бы они были динамические локальные переменные, объявленные в этой функции. Не имеется никакого способа освободить место явно.
Прототип для alloca находится в "stdlib.h". Эта функция - BSD расширение.
      void * alloca (size _t size); (функция)
Возвращаемое значение alloca - адрес блока из size байтов памяти, размещенного в области данных вызывающей функции. 
Не используйте alloca внутри аргументов обращения к функции, Вы получите непредсказуемые результаты, потому что стек-пространство для alloca появится на стеке в середине пространства для аргументов функции. Пример того, что нужно избегать - foo (x, alloca (4), y).

Примеры alloca


Пример использования alloca, это функция, которая открывает имя файла, сделанное из связывания двух строк аргумента, и возвращает описатель файла или минус один выражая отказ:
      intopen2 (char * str1, char * str2, int flags, int mode)
      {
       char *name = (char *) alloca (strlen (str1) + strlen (str2) + 1);
       strcpy (name, str1);
       strcat (name, str2);
       return open (name, flags, mode);
      }
А вот, как Вы получили бы те же самые результаты с malloc и free: 
      intopen2 (char * str1, char * str2, int flags, int mode)
      {
       char *name = (char *) malloc (strlen (str1) + strlen (str2) + 1);
       int desc;
       if (name == 0) fatal ("превышенна виртуальная память ");
       strcpy (name, str1);
       strcat (name, str2);
       desc = (name, flags, mode);
       free (name);
       desc;
      }
Вы видите, что это более просто с alloca. Но alloca имеет другие, более важные преимущества, и некоторые недостатки. 

Преимущества alloca


Имеются причины, почему alloca может быть предпочтительнее malloc:
  • Использование alloca занимает мало места и очень быстро. (Это открыто кодируется компилятором GNU С.)
  • С тех пор alloca не имеет отдельных пулов для различных размеров блока, место, используемое для блока любого размера может многократно использоваться и для любого другого. alloca не вызывает фрагментацию памяти.
  • Нелокальные выходы, выполненные через longjmp (см. Главу 20 [Нелокальные выходы]) автоматически освобождают место, размещенное alloca, когда они выходят из функции, которая вызвала alloca. Это ­ наиболее важная причина использовать alloca.
Чтобы иллюстрировать это, предположите, что Вы имеете функцию open_or_report_error, которая возвращает описатель открытого, если она успешно завершается, но не возвращается к вызывающему оператору, если она терпит неудачу. Если файл не может быть открыт, она печатает сообщение об ошибках и переходит с командного уровня вашей программы, используя longjmp. Давайте изменим open2 (см. раздел 3.5.1 [Примеры alloca]) чтобы использовать эту подпрограмму: 
      intopen2 (char * str1, char * str2, int flags, int mode)
      {
       char *name = (char *) alloca (strlen (str1) + strlen (str2) + 1);
       strcpy (name, str1); strcat (name, str2);
       return open_or_report_error (name, flags, mode);
      }
Из-за способа работы alloca, память, которую она резервирует, освобождается даже, когда происходит ошибка, без специального усилия. 
А предыдущее определение open2 (которое использует malloc и free) допустило бы утечку памяти, если это было бы изменено таким образом,. Даже если Вы хотите сделать большее количество изменений, чтобы устранить это, не имеется никакого простого способа делать так.

Недостатки alloca


Здесь недостатки alloca по сравнению с malloc:
  • Если, Вы пробуете зарезервировать большее количество памяти чем машина, может обеспечивать, Вы не получаете чистое сообщение об ошибках. Взамен Вы получаете фатальный сигнал подобно тому, который Вы получили бы из бесконечной рекурсии; возможно нарушение сегментации (см. раздел 21.2.1 [Сигналы об ошибках в программе]).
  • Некоторые не-GNU системы будут не в состоянии поддерживать alloca, так что она менее переносима. Однако, более медленная эмуляция alloca, которую пишут на C доступна для использования в системах с этой неточностью.

                    

GNU C массивы с переменным размером


В GNU C, Вы можете заменять большинство использований alloca с массивом переменного размера. Вот, как выглядела бы open2:
      int open2(char * str1, char * str2, int flags, int mode)
      {
       char name [strlen (str1) + strlen(str2) + 1];
       strcpy (name, str1);
       strcat (name, str2);
       return open (name, flags,mode);
      }
Но alloca не всегда эквивалентна динамическому массиву, по следующим причинам: 
  • Место динамического массива освобождается в конце области действия имени массива. Место, размещенное alloca остается до конца этой функции.
  • Возможно использовать alloca внутри цикла, резервируя дополнительный блок на каждой итерации. Это невозможно с динамическими массивами.
Обратите внимание: если Вы смешиваете использование alloca и динамических массивов внутри одной функции, выход из области, в который динамический массив был объявлен, освобождает все блоки, размещенные alloca во время выполнения этой области. 

3.6 Настройка программы распределения


Любая система динамического распределения памяти имеет непроизводительные затраты: количество места, которое она использует ­ больше чем количество, о котором программа просит. Программа настройки распределения памяти достигает очень низких непроизводительных затрат, перемещая блоки в памяти по мере необходимости, по собственной инициативе.

Понятия настройки резервирования


Когда Вы резервируете блок malloc, адрес блока никогда не изменяется, если Вы не используете realloc, чтобы изменить размер. Таким образом, Вы можете безопасно сохранять адрес в различных местах, временно или постоянно, как захотите. Это не безопасно, когда Вы используете программу настройки распределения памяти, потому что любые переместимые блоки могут двигаться всякий раз, когда Вы зарезервируете память в любом режиме. Даже вызов malloc или realloc может перемещать переместимые блоки.
Для каждого переместимого блока, Вы должны делать дескриптор указываемого объекта в памяти, предназначенный для того, чтобы сохранять адрес этого блока. Программа настройки распределения знает, где находится дескриптор каждого блока, и модифицирует адрес, сохраненный там всякий раз, когда она перемещает блок, так, чтобы дескриптор всегда указывал на блок. Каждый раз Вы обращаетесь к содержимому блока, Вы должны брать адрес из дескриптора.
Вызов любой функции программы настройки распределения из обработчика сигнала почти всегда неправилен, потому что сигнал мог появиться в любое время. Единственый способ делать это безопасно состоит в том, чтобы блокировать сигнал для любого доступа к содержимому любого переместимого блока, не удобен для работы. См. раздел 21.4.6 [Неповторное вхождение].

Распределение и освобождение переместимых блоков


В описаниях ниже, handleptr обозначает адрес дескриптора. Все функции объявлены в "malloc.h"; все являются расширениями GNU.
      void * r_alloc (void ** handleptr, size _t size) (функция)
Эта функция резервирует переместимый блок размера size. Она сохраняет адрес блока в * handleptr и возвращает непустой указатель в случае успеха. 
Если r_alloc не может получить необходимое место, она сохраняет пустой указатель в *handleptr, и возвращает пустой указатель.
      void r_alloc_free (void ** handleptr) (функция)
Эта функция - способ освободить переместимый блок. Она освобождает блок, на который указывает *handleptr, и сохраняет пустой указатель в *handleptr, чтобы показать что он больше не указывает на размещенный блок. 
      void * r_re_alloc (void ** handleptr, size _t size) (функция)
Функция r_re_alloc корректирует размер блока на который указывает *handleptr, делая его size байт длиной. Она сохраняет адрес измененного блока в *handleptr и возвращает непустой указатель в случае успеха. 
Если достаточная память не доступна, эта функция, возвращает пустой указатель и не изменяет *handleptr.

3.7 Предупреждения относительно использования памяти


Вы можете просить о предупреждениях для программ исчерпывающих пространство памяти, вызывая memory_warnings. Она указывает, чтобы malloc проверял использование памяти, каждый раз когда он просит о большем количестве памяти из операционной системы. Это - расширение GNU, объявленное в "malloc.h".
      void memory_warnings (void *start, void (* warn_func) (const char*)) (функция)
Вызывайте эту функцию, чтобы запросить предупреждения для приближающегося исчерпывания виртуальной памяти. 
Аргумент start говорит, где начинается место данных в памяти. Программа распределения сравнивает его c последним используемым адресом и с пределом места данных, определяя долю доступной памяти. Если Вы указываете нуль как начало, то по умолчанию, используется наиболее вероятное значение.
malloc может вызывать функцию warn_func, чтобы предупредить Вас. Она вызывается со строкой (предупреждающим сообщением) как аргументом. Обычно она должнаот образить строку для пользователя.
Предупреждения приходят, когда память становится полной на 75%, на 85%, и на 95%. Если занято более чем 95 % Вы получаете другое предупреждение каждый раз увеличивая используемую память.

4. Обработчики символов


Программы которве работтают с символами и строками часто должны классифицировать символ как букву, цифру, пробел, и так далее и выполнять операции замены регистра на символах. Функции в заголовочном файле "ctype.h" предусмотрены для этой цели.
Так как выбор стандарта и набора символов может изменять классификации специфических символьных кодов, все эти функции зависят от текущего стандарта. (Точнее, на них воздействует стандарт, в настоящее время выбранный для классификации символов LC_CTYPE; см. раздел 19.3 [Категории стандарта] )

4.1 Классификация символов


Этот раздел объясняет библиотечные функции для классификации символов. Например, isalpha - функция, чтобы проверить буквенный ли символ. Она имеет один аргумент, символ для проверки, и возвращает целое число отличное от нуля, если символ буквенный, и нуль иначе. Ее можно использовть примерно так:
      if (isalpha (c)) printf ("Символ \"%c\" является буквой.\n", c);

Каждая из функций в этом разделе проверяет на принадлежность специфическому классу символов; каждая имеет имя, начинающееся с 'is'. Каждая из них имеет один аргумент, который является проверяемым символом, и возвращает int, который обрабатывается как логическое значение. Символьный аргумент передан как int, и это может быть постоянное значение EOF вместо реального символа.
Атрибуты любого данного символа могут измениться между стандартами. См. Главу 19 [Стандарты], для уточнения информации относительно стандартов.
Эти функции объявлены в заголовочном файле "ctype.h".
int islower (int c) (функция)

Возвращает истину, если C - символ нижнего регистра.

int isupper (int c) (функция)

Возвращает истину, если C - символ верхнего регистра.

int isalpha (int c) (функция)

Возвращает истину, если C - буквенный символ (буква). Если islower или isupper - истина для символа, то isalpha - также истина.

В некоторых стандартах , могут иметься дополнительные символы, для которых isalpha является истинной, и которые не являются, ни строчными буквами, ни символами верхнего регистра. Но в стандарте "C", не имеется никаких таких дополнительных символов.

int isdigit (int c) (функция)

Возвращает истину, если C - десятичная цифра (от "0" до "9").

int isalnum (int c) (функция)

Возвращает истину, если C - алфавитно-цифровой символ (символ или цифра); другими словами, если или isalpha или isdigit - истина для символа, то isalnum - также истина.

int isxdigit (int c) (функция)

Возвращает истину, если C - шестнадцатеричная цифра. Шестнадцатеричные цифры включают нормальные десятичные цифры от "0" до "9" и символы от "А" до "F" и от "a" до "f".

int ispunct ( int c) (функция)

Возвращает истину, если C - символ пунктуации. Это означает любой символ печати, который не алфавитно-цифровой или пробел.

int isspace (int c) (функция)

Возвращает истину, если C - символ пропуска. В стандартном расположении, isspace возвращает истину только для стандартных символов пробела:

      " " пробел
      "\f" перевод страницы
      "\n" символ перевода строки
      "\r" возврат каретки
      "\t" горизонтальная метка табуляции
      "\v" вертикальная метка табуляции
int isblank (int c) (функция)

Возвращает истину, если C - знак пропуска; то есть пробел или метка табуляции. Эта функция - расширение GNU.

int isgraph (int c) (функция)

Возвращает истину, если C - графический символ; то есть символ, который имеет glyph, связанный с этим. Символы пропуска не рассматриваются как графические символы.

int isprint (int c) (функция)

Возвращает истину, если C - символ печати. Символы печати включают все графические символы, плюс пробел (" ").

int iscntrl (int c) (функция)

Возвращает истину, если C - управляющий символ (то есть символ, который не является символом печати).

int isascii (int c) (функция)

Возвращает истину, если C 7-битовое символьное значение без знака, которое вписываться в US/UK ASCII набор символов. Эта функция - BSD расширение и - также SVID расширение.


                    

4.2 Замена регистра


Этот раздел объясняет библиотечные функции для выполнения преобразований типа замены регистра символаов. Например, toupper преобразовывает любой символ в верхний регистр если возможно. Если символ не может быть преобразован, toupper, возвращает его неизменным.
Эти функции берут один аргумент типа int, который является символом, чтобы преобразовывать, и возвратить преобразованный символ как int. Если преобразование не применимо данному аргументу, аргумент, возвращается неизмененным.
Примечание относительно совместимости: В до-ANSI диалектах C, вместо того, чтобы возвращать неизмененный аргумент, эти функции могут терпеть неудачу, когда аргумент не подит для преобразования. Таким образом для переносимости, Вы должны написать islower (c)? toupper (c): c) а не просто toupper (c).
Эти функции объявлены в заголовочном файле "ctype.h".
int tolower (int c) (функция)

Если C - символ верхнего регистра, tolower возвращает соответствующий символ нижнего регистра. C если - не символ верхнего регистра, C возвращается неизменным.

int toupper (int c) (функция)

Если С - символ нижнего регистра, tolower возвращает соответствующий символ верхнего регистра. Иначе C возвращается неизменным.

int toascii (int c) (функция)

Эта функция преобразовывает C в ASCII символ, очищая старшие биты. Эта функция - BSD расширение и - также SVID расширение.

int _tolower (int c) (функция)

Она идентична tolower, и предусматривает совместимость с SVID. См. раздел 1.2.4 [SVID].

int _toupper ( int c) (функция)

Она идентична toupper, и предусматривает совместимость с SVID.


                    

5. Утилиты для работы со строками и массивами.


Операции на строках (или массивах символов) - важная часть многих программ. Библиотека C GNU обеспечивает большой набор строковых сервисных функций, включая функции для копирования, связывания, сравнения, и поиска строк. Многие из этих функций могут также функционировать на произвольных областях памяти; например, функция memcpy может использоваться, чтобы копировать содержимое любого вида массива.
Для начинающихся С программистов довольно обычно "повторно изобретать колесо", дублируя эти функциональные возможности в их собственном коде, но знакомому с библиотечными функциями выгодно использовать их, так как это дает выгоды в эффективности и переносимости.
Например, Вы можете легко сравнивать одну строку с другим в двух строках кода C, но если Вы используете встроенную функцию strcmp, менее вероятно, что Вы сделаете ошибку. И, так как эти библиотечные функции обычно сильно оптимизированы, ваша программа может выполняться быстрее.

5.1 Представление строк


Этот раздел - быстрый обзор строковых понятий для начинающих программистов. Он описывает, как символьные строки представляются на C. Если Вы уже знакомы с этим материалом, Вы можете пропустить этот раздел.
Строка - массив объектов char. Но строковые переменные, обычно объявляется, как указатели типа char *. Такие переменные не включают пространство для текста строки; он должен быть сохранен где-нибудь в переменной типа массив, строковой константе, или динамически размещенной памяти (см. Главу 3 [Распределение памяти]). Это позволяет Вам сохранить адрес выбранного пространства памяти в переменнуюуказатель. В качестве альтернативы Вы можете сохранять пустой указатель в переменной. Пустой указатель никуда не указывает, так что попытка сослаться на строку, на которую он указывает, получит ошибку.
Обычно, пустой символ, "\0", отмечает конец строки. Например, в тестировании, чтобы видеть, что переменная p указывает на пустой символ, отмечающий конец строки, Вы можете написать ! * P или * p == "\0".
Пустой символ - совершенно отличен от пустого указателя, хотя, и представляется целым числом 0.
Строковые литералы появляются в C программе как строки символов между символами кавычек ('"'). В ANSI C, строковые литералы могут также быть сформированы строковой конкатенацией: "a" "b" - то же что "ab". Изменение строковых литералов не допускается GNU С компилятором, потому что литералы помещены в памяти только для чтения.
Символьные массивы, которые являются объявленным const, также не могут изменяться. Это - вообще хороший стиль, объявить, что немодифицируемые строковые указатели будут типа const char *, так как это часто позволяет компилятору C обнаружить случайные изменения, также как обеспечение некоторого количества документации относительно того, что ваша программа предполагает делать со строкой.
Объем памяти, размещенный для символьного массива может простираться после пустого символа, который обычно отмечает конец строки. В этом документе термин размер резервирования всегда используется, чтобы обратиться к общей сумме памяти, размещенной для строки, в то время как термин длина относится к числу символов до (но не, включая) пустого символа завершения.
Известным источником ошибок является то, что программа пробует помещать большее количество символов в строку чем позволяет размещенный размер. При написании кода, который расширяет строки или перемещает символы в массив, Вы должны быть очень осторожны, чтобы следить за длиной текста и делать явную проверку переполнения массива. Многие из библиотечных функций не делают это для Вас! Не забудьте также, что Вы должны зарезервировать дополнительный байт, чтобы содержать пустой символ, который отмечает конец строки.

5.2 Соглашения относительно строк и массивов


Эта глава описывает функции, которые работают над произвольными массивами или блоками памяти, и функции, которые являются специфическими для массивов с нулевым символом в конце.
Функции, которые функционируют на произвольных блоках памяти, имеют имена, начинающиеся "mem" (типа memcpy) и неизменно имеют аргумент, который определяет размер (в байтах) блока рабочей памяти. Аргументы массива и возвращаемые значения для этих функций имеют тип void*, и как стиль, элементы этих массивов упоминаются как "байты". Вы можете передавать любой вид указателя на эти функции, а оператор sizeof полезен при вычислении значения аргумента size.
Напротив, функции, которые функционируют специально на строках, имеют имена, начинающиеся "str" (типа strcpy) и ищут пустой символ, чтобы завершить строку вместо того, чтобы требовать, чтобы был передан явный аргумент размера. (Некоторые из этих функций принимают заданную максимальную длину, но они также проверяют преждевременное окончание с пустым символом.) аргументы массива и возвращаемые значения для этих функций имеют тип char *, и элементы массива упоминаются как "символы".
В многих случаях, имеется, и "mem" и "str" версии функции. Которая является более подходящей, зависит от контекста. Когда ваша программа манипулирует произвольными массивами или блоками памяти, Вы должны всегда использовать "mem" функции. С другой стороны, когда Вы манипулируете строками с нулевым символом в конце, обычно более удобно использовать "str" функции, если Вы не знаете длину строки заранее.

5.3 Длина строки


Вы можете получить длину строки, используя функцию strlen. Эта функция объявлена в заголовочном файле "string.h".
      size _t strlen (const char * s) (функция)

Функция strlen возвращает длину строки с нулевым символом в конце. (Другими словами, она возвращает смещение пустого символа завершения внутри массива.) Например,
strlen ("привет, мир") =>12
Когда функция strlen применяется к символьному массиву, она возвращает длину сохраненной строки, а не размер резервирования. Вы можете получить размер резервирования символьного массива, который содержит строку, используя оператор sizeof:
char string[32] = "привет, мир"; sizeof (string) => 32 strlen (string) => 12

5.4 Копирование и конкатенация


Вы можете использовать функции, описанные в этом разделе, чтобы копировать содержимое строк и массивов, или конкатенировать содержимое одной строки c другой. Эти функции объявлены в заголовочном файле "string.h".
Все эти функции возвращают адрес целевого массива.
Большинство этих функций не работает правильно, если исходный и целевой массивы накладываются. Например, если начало массива адресата накладывается на конец исходного массива, первоначальное содержимое той части исходного массива может стать записанным поверх прежде, чем это скопировано. Даже хуже, в случае строковых функций, пустой символ, отмечающий конец строки можно потерять, и функция копирования может эастревать в цикле, просматривая всю память зарезервированную для вашей программы.
Все функции, которые имеют проблемы при копировании между накладывающимися массивами, явно идентифицированы в этом руководстве. В дополнение к функциям в этом разделе, имеется несколько, других например sprintf (см. раздел 7.9.7 [Форматируемые функции вывода]) и scanf (см. раздел 7.11.8 [Форматируемые функции ввода]).
      void * memcpy (void *to, void const *from, size _t size) (функция)

Функция memcpy копирует size байт из объекта, начинающегося в from в объект, начинающийся в to. Поведение этой функции неопределено если два массива перекрываются; используйте memmove взамен, если возможно перекрывание.
Значение, возвращенное memcpy - значение to.
Вот пример того, как Вы могли бы использовать memcpy, чтобы копировать содержимое массива:
      struct foo *oldarray, *newarray;
      int arraysize;
      ...
      memcpy (new, old, arraysize * sizeof (struct foo));

      void * memmove (void *to, void const *from, size _t size) (функция)

memmove копирует size байт из from в size в to, даже если те два блока памяти перекрываются.
      void * memccpy (void *to, void const *from, int C, size _t size) (функция)

Эта функция копирует не больше, чем size байт из from в to, останавливая если найден байт соответствующий C. Возвращаемое значение ­ указатель в to на первый байт после C, или пустой указатель, если никакой байт, соответствующий C не появился в первых size байтах from.
      void * memset (void * block, int C, size _t size) (функция)

Эта функция копирует значение C (преобразованный в char без знака) в каждый из первых size байтов объекта, начинающегося с block. Она возвращает значение block.
      сhar * strcpy (char *to, const char *from) (функция)

Она копирует символы из строки from (включая пустой символ завершения) в строку to. Подобно memcpy, эта функция имеет неопределенные результаты, если строки накладываются. Возвращаемое значение - значение to.
      char * strncpy (char *to, const char *from, size _t size) (функция)

Эта функция подобна strcpy, но всегда копирует точно size символов в to.
Если длина from - больше чем size, то strncpy копирует только первые size символов.
Если длина from меньше чем size, то strncpy, копирует все from, сопровождая его достаточным количеством пустых символов, чтобы получить всего size символов. Это редко полезно, но зато определено в соответствии c ANSI стандартом.
Поведение strncpy неопределено, если строки накладываются.
Использование strncpy в противоположность strcpy - способ избежать ошибок в отношении соглашения о записи после конца размещенного пространства для to. Однако, это может также сделать вашу программу намного медленнее в одном общем случае: копирование строки, которая является возможно малой в потенциально большой буфер. В этом случае, size может быть большой, и когда это, strncpy будет тратить впустую значительное количество времени, копируя пустые символы.
      char * strdup (const char * s) (функция)

Эта функция копирует строку с нулевым символом в конце в недавно размещенную строку. Строка размещена, используя malloc; см. раздел 3.3 [Беспрепятственное резервирование].
Если malloc не может зарезервировать пространство для новой строки, strdup возвращает пустой указатель. Иначе она возвращает указатель на новую строку.
      char * stpcpy (char *to, const char *from) (функция)

Эта функция - подобно strcpy, за исключением того, что она возвращает указатель на конец строки to (то есть адрес пустого символа завершения) а не на начало.
Например, эта программа использует stpcpy, чтобы конкатенировать "foo" и "bar" и печатает "foobar".
      #include 
      #include 
      intmain (void)
      {
       char buffer[10];
       char *to = buffer;
       to = stpcpy (to, "foo");
       to = stpcpy (to, "bar");
       puts (buffer);
       return 0;
      }

Эта функция - не часть ANSI или POSIX стандартов, и не обычна в системах UNIX, но мы не изобретали ее. Возможно она исходит из MS-DOS.
Поведение неопределено, если строки накладываются.
      сhar * strcat (char * to, const char *from) (функция)

Функция strcat подобна strcpy, за исключением того, что символы из from добавляются или конкатенируются к концу to, вместо того, чтобы записывать поверх него. То есть первый символ из from накладывается на пустой символ, отмечающий конец to.
Эквивалентное определение для strcat было бы:
      char * strcat (char *to, const char *from)
      {
       strcpy (to + strlen to, from);
       return to;
      }

Эта функция имеет неопределенные результаты, если строки накладываются.
      char * strncat (char *to, const char *from, size _t size) (функция)

Эта функция - подобнa strcat за исключением того, что не больше чем size символов из from конкатенируются к концу to. Одиночный пустой символ также всегда конкатенируется к to, так что общая конечая длина to должна быть по крайней мере на size + 1 байт больше чем начальная длина.
Функция strncat могла быть выполнена примерно так:
      char * strncat (char *to, const char *from, size_t size)
      {
       strncpy (to + strlen (to), from, size);
       return to;
      }

Поведение strncat неопределено, если строки накладываются.
Вот пример, показывающий использование strncpy и strncat. Обратите внимание, как вычислен параметр size, в обращении к strncat, чтобы избежать переполнять символьный массив buffer.
      #include 
      #include 
      #define SIZE 10
      static char buffer[SIZE];
      main ()
      {
       strncpy (buffer, "hello", SIZE);
       puts (buffer);
       strncat (buffer, ", world", SIZE - strlen (buffer) - 1);
       puts (buffer);
      }

Вывод, произведенный этой программой будет:
      hellohello, wo

      void * bcopy (void *from, void const *to, size _t size) (функция)

Она является частично устаревшим вариантом для memmove, и происходит от BSD. Обратите внимание, что она не совершенно эквивалентна memmove, потому что аргументы не в том же самом порядке.
      void * bzero (void *block, size _t size) (функция)

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

5.5 Сравнение строк/массивов


Вы можете использовать функции в этого раздела, чтобы выполнить сравнение на содержимое строк и массивов. Также как для проверки равенства, эти функции могут использоваться как функции упорядочения для операций сортировки. См. Главу 15 [Поиск и сортировка].
В отличие от большинства операций сравнения в C, строковые функции сравнения возвращают значение отличное от нуля, если строки - не эквивалентны. Знак значения указывает относительное упорядочение первых символов в строках, которые - не эквивалентны: отрицательное значение указывает, что первая строка - "меньше" чем вторая, в то время как положительное значение указывает, что первая строка "больше".
Если Вы используете эти функции только, чтобы проверить равенство, для большей чистоты программы, лучше задать их как макроопределения, примерно так:
      #define str_eq (s1, s2) (! Strcmp ((s1), (s2)))

Все эти функции объявлены в заголовочном файле "string.h".
      int memcmp (void const * a1, void const * a2, size _t size) (функция)

Функция memcmp сравнивает size байт памяти, начинающиеся в a1 с size байтами памяти, начинающимися в a2. Возвращенное значение имеет тот же самый знак как разность между первой отличающейся парой байтов (интерпретируемых как объекты char без знака).
Если содержимое двух блоков равно, memcmp, возвращает 0.
На произвольных массивах, функция memcmp обычно полезна для тестирования равенства. Обычно не имеет смысла делать байтовое сравнение упорядочения на не байтовых массивах. Например, байтовое сравнение на байтах, которые составляют числа с плавающей запятой не должно правдоподобно сообщить Вам что - нибудь относительно связи между значениями чисел с плавающей запятой.
Вы должны также быть внимательны при использовании memcmp, для сравнения объектов, которые могут содержать "дырки", типа дополнения, вставленного в объекты структуры, чтобы предписать требования выравнивания, дополнительного пространства в конце объединений, и дополнительных символов в концах строк, чьи длины меньше чем затребовано при размещении.
Содержимое этих "дырок" неопределено и может вызывать странное поведение при выполнении байтового сравнения. Для более предсказуемых результатов, выполните явное покомпонентное сравнение.
Например, пусть дано определение типов структуры подобно:
      struct foo {
       unsigned char tag;
       union{double f; long i; char *p;}
       value;
      };

Вам лучше написать специализированные функции сравнения, чтобы сравнить объекты struct foo вместо того, чтобы сравнить их memcmp.
      int strcmp (const char * s1, const char * s2) (функция)

Функция strcmp сравнивает строку s1 c s2, возвращая значение, которое имеет тот же самый знак как различие между первой отличающейся парой символов (интерпретируемых как объекты char без знака).
Если две строки равны, strcmp, возвращает 0.
Следствие упорядочения, используемого strcmp - то, что, если s1 является начальной подстрокой s2, то s1 "меньше чем" s2.
      int strcasecmp (const char * s1, const char * s2) (функция)

Эта функция подобна strcmp, за исключением того, что разногласия игнорируются.
      strcasecmp происходит от BSD.

                    
      int strncasecmp (const char * s1, const char * s2) (функция)

Эта функция - подобна strncmp, за исключением того, что разногласия игнорируются.
      strncasecmp - расширение GNU.

                    
      int strncmp (const char * s1, const char * s2, size _t size) (функция)

Эта функция подобна strcmp, за исключением того, что сравниваются не больше, чем size символов. Другими словами, если две строки совпадают в их первых size символах, возвращаемое значение - нуль.
Имеются некоторые примеры, показывающие использование strcmp и strncmp. Эти примеры подразумевают использование набора символов ASCII. (Если используется некоторый другой набор символов скажем, расширенный двоично-десятичный код обмена информацией, взамен, то glyphs связаны с различными числовыми кодами, и возвращаемые значения, и порядок могут отличиться.)
      strcmp ("привет", "привет")
      => 0 /* Эти две строки одинаковы. */
      strcmp ("привет", "Привет")
      => 33 /* Сравнение чувствительно к регистру. */
      strcmp ("привет", "мир")
      => -2 /* символ "п" меньше чем "м". */
      strcmp ("привет", "привет, мир")
      => -44 /* Сравнение пустого символа с запятой. */
      strncmp ("привет", "привет, мир", 5)
      => 0 /* начальные 5 символов - те же самые. */
      strncmp ("привет, мир","привет, глупый мир!!!", 5)
      => 0 /* начальные 5 символов - те же самые. */
      int bcmp (void const * a1, void const * a2, size _t size) (функция)

Это - устаревший побочный результат исследования для memcmp, происходит от BSD.

5.6 Функции для объединений


В некоторых местах соглашения лексикографического упорядочения отличаются от строгого числового упорядочения символьных кодов. Например, в Испании большинство букв с диакритическими знаками, но буквы с диакритическими знаками не считаются различными символами в целях объединения. С другой стороны, последовательность с двумя символами "ll" обрабатывается как одна буква, которая объединена с "l".
Вы можете использовать функции strcoll и strxfrm (объявленные в заголовочном файле "string.h") чтобы сравнивать строки, использующие объединение упорядочивания соответствующее для данной местности. Стандарт, используемое этими функциями в частности может быть определено, устанавливая стандарт для класса LC_COLLATE; см. Главу 19 [Стандарты].
В стандартном расположении C, последовательность объединений для strcoll - таже что для strcmp.
Действительно, способ, которым эта функция работает применяя отображение, чтобы трансформировать символы в строку, в последовательность байтов которая представляет позицию строки в последовательности объединений текущего расположения. Сравнение двух таких последовательностей байтов в простом режиме эквивалентно сравнению строк с последовательностью объединений расположения.
Функция strcoll выполняет эту трансляцию неявно, чтобы делать одно сравнение. А, strxfrm выполняет отображение явно. Если Вы делаете многократное сравнение, используя ту же самую строку или набор строк, то более эффективноиспользовать strxfrm, чтобы трансформировать все строки только один раз, и впоследствии сравнивать преобразованные строки strcmp.
      int strcoll (const char * s1, const char * s2) (функция)

Функция strcoll подобна strcmp, но использует последовательность объединений данного расположения для объединения (LC_COLLATE стандарт).
Вот пример сортировки массива строк, с использованием strcoll, чтобы сравнить их. Фактический алгоритм сортировки здесь не написан; он исходит из qsort (см. раздел 15.3 [Функции сортировки массива]). Работа кода показанного здесь, говорит, как сравнивать строки при их сортировке. (Позже в этом разделе, мы покажем способ делать это, более эффективно используя strxfrm.)
      /* Это - функция сравнения, используемая в qsort. */
      intcompare_elements (char **p1, char **p2)
      {
       return strcoll (*p1,*p2);
      }

      /* Это - точка входа к функции сортировки строк, использующей
 последовательность объединений расположения. */
      void sort_strings (char **array, int nstrings)
      { /* Сортировка временного массива, сравнивая строки. */
       qsort (array, sizeof (char *), nstrings, compare_elements);
      }

                    
      size _t strxfrm (char *to, const char *from, size _t size) (функция)

Функция strxfrm трансформирует строку, используя преобразование объединения, определенное стандартом, в настоящее время выбранным для объединения, и сохраняет преобразованную строку в массиве to.
Поведение неопределено если строки to и from перекрываются; см. раздел 5.4 [Копирование и конкатенация].
Возвращаемое значение - длина всей преобразованной строки. На это значение не воздействует значение size, но если она большее чем size, это означает, что преобразованная строка полностью не поместилась в массиве to.
Чтобы получать целую преобразованную строку, вызовите strxfrm снова с большим массивом вывода.
Преобразованная строка может быть больше чем первоначальная строка, а может также быть более короткой.
Если size - нуль, никакие символы не сохранены в to. В этом случае, strxfrm просто возвращает число символов, которое было бы длиной преобразованной строки. Это полезно для определения какую строку зарезервировать. Не имеет значение, что будет в to, если size - нуль; может быть даже пустой указатель.
Вот пример того, как Вы можете использовать strxfrm когда Вы планируете делать много сравнений. Он делает то же самое что и предыдущий пример, но намного быстрее, потому что он должен трансформировать каждую строку только один раз, независимо от того сколько раз она сравнивается с другими строками. Даже времени для резервирования и освобождения памяти нужно намного меньше чем, когда имеются много строк.
      struct sorter { char *input; char *transformed; };

                    
      /* Это - функция сравнения, используемая qsort для сортировки
 массива структур. */
      int compare_elements (struct sorter *p1, struct sorter *p2)
      {
       return strcmp (p1->transformed, p2->transformed);
      }

      /* Это - точка входа функции сортировки строк, использующей
 последовательность объединений расположения. */
      void sort_strings_fast (char **array, int nstrings)
      {
       struct sorter temp_array[nstrings];
       int i;
      /* Устанавливает temp_array. Каждый элемент содержит одну входную
 строку и преобразованную строку. */
       for (i = 0; i < nstrings; i++)
       {
        size_t length = strlen (array[i]) * 2;
        temp_array[i].input = array[i];
      /* Трансформирует array[i] . Сначала, пробует буфер, возможно
 достаточно большой. */
        while (1)
        {
         char *transformed = (char *) xmalloc (length);
         if (strxfrm (transformed, array[i], length) < length)
         {
          temp_array[i].transformed = transformed;
          break;
         } /* Попытка снова с еще большим буфером. */
         free (transformed); length *= 2;
        }
       }
      }

      /* Сортировка temp_array, сравнивая преобразованные строки. */
      qsort (temp_array, sizeof (struct sorter), nstrings,
 compare_elements);

      /* Помещает элементы обратно в постоянный массив в их сортированном
 порядке. */
      for (i = 0; i < nstrings; i++) array[i] = temp_array[i].input;

      /* Освобождают строки, которые мы зарезервировали. */
      for (i = 0; i < nstrings; i++) free (temp_array[i].transformed);}

Примечание относительно совместимости: функции объединения строк ­ новая возможность ANSI C., более старые диалекты C не имеют никакой эквивалентной возможности.

5.7 Функции поиска


Этот раздел описывает библиотечные функции, которые выполняют различные виды операций поиска в строках и массивах. Эти функции объявлены в заголовочном файле "string.h".
      void * memchr (void const *block, int с, size _t size) (функция)

Эта функция находит первое вхождение байта с (преобразованного в char без знака) в начальных size байтах объекта, начинающегося в block. Возвращаемое значение - указатель на размещенный байт, или пустой указатель, если не было найдено никакого соответствия.
      сhar * strchr (const char *string, int c) (функция)

Функция strchr находит первое вхождение символа с (преобразованного в char) в строке с нулевым символом в конце, начинающейся в string. Возвращаемое значение - указатель на размещенный символ, или пустой указатель, если никакое соответствие не было найдено.
Например,
      strchr ("привет, мир", "в")
      => "вет, мир"
      strchr ("привет, мир", "?")
      => NULL

Пустой символ завершения является частью строки, так что Вы можете использовать эту функцию, для получения указателя на конец строки, определяя пустой символ как значение аргумента с.
      char * index (const char *string, int c) (функция) - другое имя для strchr.

                    
      сhar * strrchr (const char *string, int c) (функция)

Функция strrchr - подобна strchr, за исключением того, что она ищет в обратном направлении, с конца строки (а не сначала).
Например,
      strrchr ("привет, мир", "и")
      => "ир"

                    
      char * rindex (const char *string, int c) (функция)

rindex - другое имя для strrchr.
      char * strstr (const char * haystack, const char * needle) (функция)

Она подобна strchr, за исключением того, что она ищет в haystack подстроку needle, а не только одиночный символ. Она возвращает указатель в строку haystack, который является первым символом подстроки, или пустой указатель, если никакого соответствия не было найдено. Если needle - пустая строка, то функция возвращает haystack.
Например,
      strstr ("привет, мир","в")
      => "вет, мир"
      trstr ("привет, мир","ми")
      => "мир"

void * memmem (const void *needle, size_t needle_len, const void *haystack, size_t haystack_len) (функция)
Она подобна strstr, но needle и haystack байтовые массивы, а не строки с нулевым символом в конце. needle_len - длина needle, а haystack_len - длина haystack.
Эта функция - расширение GNU.
      size_t strspn (const char *string, const char *skipset) (функция)

Функция strspn ("строковый диапазон") возвращает длину начальной подстроки строки, которая состоит полностью из символов, которые являются элементами набора, заданного строкой skipset. Порядок символов в skipset не важен.
Например,
      strspn ("привет, мир","абвгдежзийклмнопрстуфхцчшщъыьэюя"))
      => 6

                    
      size_t strcspn (const char *string, const char *stopset) (функция)

Функция strcspn ("строковый диапазон дополнения") возвращает длину начальной подстроки строки, которая состоит полностью из символов, которые - не элементы набора, заданного строкой stopset. (Другими словами, она возвращает смещение первого символа в строке, которая является элементом набора stopset.)
Например,
      strcspn ("привет, мир","\t\n,.;!?")
      => 6

                    
      char * strpbrk (const char *string, const char *stopset) (функция)

strpbrk ("строковое прерывание указателя") то же что strcspn, за исключением того, что она возвращает указатель на первый символ в строке, который является элементом набора stopset вместо длины начальной подстроки. Это возвращает пустой указатель, если никакой символ из stopset не найден.
Например,
      strpbrk ("привет, мир","\t\n,.;!?")
      => ",мир"

                    

5.8 Поиск лексем в строке


В программах довольно часто возникает потребность сделать некоторые простые виды лексического и синтаксического анализа, типа разбивания командной строки в лексемы. Вы можете делать это функцией strtok, объявленной в заголовочном файле "string.h".
      char * strtok (char *newstring, const char *delimiters) (функция)

Строку можно разбить в лексемы, делая ряд обращений к функции strtok.
Строка, которую нужно разбивать передается как newstring только при первом обращении. Функция strtok использует ее, чтобы установить некоторую внутреннюю информацию о состоянии. Последующие обращения, чтобы получить дополнительные лексемы из той же самой строки обозначаются передачей пустого указателя как аргумента. Вызов strtok с другим не-пустым символом newstring повторно инициализирует информацию о состоянии. Гарантируется, что никакая другая библиотечная функция (которая смешала бы эту внутреннюю информацию о состоянии) никогда не вызовет strtok.
Аргумент delimiters - строка, которая определяет набор разделителей, которые могут окружать извлекаемую лексему. Все начальные символы, которые являются элементами этого набора, отбрасываются. Первый символ, который не является элементом этого набора разделителей, отмечает начало следующей лексемы. Конец лексемы находится, как следующий символ, который является элементом набора разделителей. Этот символ в первоначальной строке newstring зменяется пустым символом, и возвращается указатель на начало лексемы в newstring.
При следующем обращении к strtok, поиск начинается со следующего символа после того который отмечен концом предыдущей лексемы. Обратите внимание, что набор разделителей не должен быть тем же самым при каждом вызове strtok.
Если конец строки newstring достигнут, или если остаточный член от строки состоит только из символов - разделителей, strtok, возвращает пустой указатель.
Предупреждение: С тех пор как strtok изменит строку, которую она анализирует, всегда копируйте строку во временный буфер перед синтаксическим ее анализом strtok. Если Вы разрешаете, чтобы strtok изменил строку, которая исходила из другой части вашей программы, Вы создаете проблему; та строка может быть частью структуры данных, которая могла использоваться для других целей в течение синтаксического анализа, в то время как чередование strtok делает структуру данных, временно неточной.
Строка, на которой Вы действуете, могла быть и константой. И, когда strtok попробует изменять ее, ваша программа получит фатальный сигнал о записи в память распределенную тоько для чтения. См. раздел 21.2.1 [Сигналы ошибки в программе].
Это - частный случай общего принципа: если часть программы не имеет цели изменить некоторую структуру данных, то ошибочно изменять структуру данных даже временно.
Функция strtok не повторно используема. См. раздел 21.4.6 [Неповторная входимость], для обсуждения где и почему повторная входимость важна.
Вот простой пример, показывающий использование strtok.
      #include 
      #include 
      . . .
      char string[] = "words separated by spaces -- and, punctuation!";
      const char delimiters[] = " .,;:!-";
      char *token;
      . . .
      token = strtok (string, delimiters);  /* token => "words" */
      token = strtok (NULL, delimiters);   /* token => "separated" */
      token = strtok (NULL, delimiters);   /* token => "by" */
      token = strtok (NULL, delimiters);   /* token => "spaces" */
      token = strtok (NULL, delimiters);   /* token => "and" */
      token = strtok (NULL, delimiters);   /* token => "punctuation" */
      token = strtok (NULL, delimiters);   /* token => NULL */

                  

Обсудить данную тему на нашем форуме "Все о Linux"