Вперед Назад Содержание

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 <string.h>
      #include <stdio.h>
      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 <string.h>
      #include <stdio.h>
      #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 <string.h>
      #include <stddef.h>
      . . .
      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 */


Вперед Назад Содержание