Немного о компьютере

Man strtok_r (3): извлечение элементов (токенов) из строки. Описание функций языка си Исходный код программы

#include char *strtok(char *str1 , const char *str2 );

Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1 . Символы, образующие строку, адресуемую параметром str2 , представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.

В версии С99 к параметрам str1 и str2 применен квалификатор restrict .

Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok() параметр str1 должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра str1 нужно использовать нулевой указатель. Этим способом вся строка разбивается на лексемы.

При каждом обращении к функции strtok() можно использовать различные наборы разделителей.

Пример

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

Травка|зеленеет|солнышко|блестит #include #include int main(void) { char *p; p = strtok("Травка зеленеет, солнышко блестит", " "); printf(p); do { p = strtok("\0", ", "); if(p) printf("|%s", p); } while(p); return 0; }

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

В языке программирования C функции для работы со строками объявляются в заголовочном файле string.h, который надо не забывать подключать к своему исходному коду. Существует около двадцати функций для работы со строками. Среди них есть те, которые осуществляют поиск символов в строке, функции сравнения, копирования строк, а также более специфические. Перечень и описание большинства существующих на данный момент в языке C функций можно найти в приложении книги Б. Кернигана, Д. Ритчи "Язык программирования C. Второе издание".

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

Например, функция strcpy() имеет такое объявление: char *strcpy (char *, const char*) . Она копирует строку, на которую указывает второй параметр, в строку, на которую указывает первый параметр. Таким образом первый параметр изменяется. Кроме того, функция возвращает указатель на первый символ строки:

char s1[ 10 ] , s2[ 10 ] ; char * s3; s3 = s2; gets (s1) ; s3 = strcpy (s2, s1) ; puts (s2) ; puts (s3) ; printf ("%p, %p\n " , s2, s3) ;

Здесь s2 и s3 указывают на один и тот же символ (printf() выводит одинаковые адреса). Однако то, что возвращает strcpy() , нельзя присвоить массиву. Результат работы этой функции обычно ничему не присваивают; бывает достаточно того, что она просто изменяет одну из переданных по указателю строк.

Другое дело, такие функции как strlen() или strcmp() , которые не изменяют параметры, а вызываются ради результата. Функция strcmp() сравнивает две строки-аргумента по буквам (лексикографически) и возвращает 0, -1 или 1. Например, вызов strcmp("boy", "body") вернет 1, т.к. код буквы "y" больше буквы "d". Вызов strcmp("body", "boy") вернет -1, т.к. первый аргумент лексикографически меньше второго.

Функция strtok()

С помощью функции strtok() можно разбить строку на отдельные части (лексемы). Объявление этой функции выглядит так char *strtok (char *, const char *) . При первом вызове функции в качестве первого параметра указывается строка, которую требуется разбить. Вторым параметром указывается строка-разделитель. При последующих вызовах функции для этой же строки первым параметром должен быть NULL, т.к. функция уже "запомнила" с чем работает. Рассмотрим пример:

char str = "one, two, three, four, five" ; char * sp; sp = strtok (str, ", " ) ; while (sp) { puts (sp) ; sp = strtok (NULL, ", " ) ; }

В результате выполнения данного кода на экран в столбик выводятся слова:

One two three four five

При первом вызове strtok() в функцию передается указатель на первый символ массива и строка-разделитель. После этого вызова массив str изменяется, в нем остается только слово "one", также функция возвращает указатель на это слово, который присваивается sp.

Хотя мы потеряли остаток массива в вызывающей функции, однако внутри strtok() сохраняется указатель на остаток массива. Когда передается NULL, функция "знает", что надо работать с этим "хвостом".

Копирование частей строк

Когда требуется просто соединить две строки, то проблема легко решается с помощью вызова функции strcat() , которая к концу первого аргумента присоединяет второй. Похожая функция strncat() присоединяет n символов второй строки к первой. n указывается в качестве третьего параметра.

Что если ситуация более сложная? Например, есть две непустые строки и надо соединить начало первой и конец второй. Сделать это можно с помощью функции strcpy() , если передавать ссылки не на первые символы строк:

char s1[ 20 ] = "Peter Smith" , s2 = "Julia Roberts" ; strcpy (s1+ 5 , s2+ 5 ) ; puts (s1) ;

В данном случае на экране будет выведено "Peter Roberts". Почему так произошло? В функцию strcpy() был передан указатель на шестой символ первой строки. Это привело к тому, что при копировании символы этой строки затираются только начиная с 6-го, т.к. strcpy() о предыдущих символах ничего не "знает". В качестве второго аргумента также передается только часть строки, которая и копируется в первую.

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

char s1[ 20 ] = "one three" , s2[ 20 ] = "two" ; strcpy (s2+ 3 , s1+ 3 ) ; strcpy (s1+ 4 , s2) ; puts (s1) ;

Здесь сначала во вторую строку копируется конец первой, получается "two three". Затем в первую строку, минуя ее начало, копируется вторая.

Описание некоторых функций для работы со строками

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

  • char *strchr (const char *, int c) . Возвращает указатель на первое вхождение символа с в строку. Возвращает NULL, если такого символа в строке нет.
  • char *strstr (const char *s2, const char *s1) . Возвращает указатель на первое вхождение строки s1 в строку s2. Если совпадений нет, возвращает NULL.
  • char *strncpy (char *, const char *, size_t n) . Копирует n символов второй строки в первую.
  • size_t strspn (const char *, const char *) . Возвращает длину начала первой строки, в которую входят символы, из которых состоит вторая строка.

char far * far _fstrtok(const char far *str1, const char far *str2)

Описание:

Функция strtok() возвращает указатель на следующую лексему в строке, на которую указывает str1. Символы из строки, на которую указывает str2, используются как ограничители, определяю­щие лексему. Если лексема не найдена, возвращается NULL.

Во время первого вызова функции strtok() в качестве указателя в самом деле используется str1. При последующих вызовах в качестве первого аргумента используется NULL. Таким образом вся строка может быть разбита на лексемы.

Важно понимать, что функция strtok() модифицирует строку, на которую указывает str1. Каж­дый раз, когда найдена лексема, на месте, где был найден ограничитель, помещается нулевой символ. Таким образом strtok() продвигается вдоль строки.

При каждом вызове strtok() можно варьировать набор ограничителей.

Функция _fstrtok() является FAR-версией рассматриваемой функции.

Следующая программа разбивает на лексемы строку «The summer soldier, the sunshine patriot», используя в качестве ограничителей пробелы и запятые. В результате работы программы будет сформирована строка следующего вида: «The | summer | soldier | the | sunshine | patriot».
#include
#include
int main(void )
{
char * p;
p = strtok ("The summer soldier, the sunshine patriot" , " " ) ;
printf (p) ;
do {
p= strtok ("\0 " , ", " ) ;
if (p) printf ("|% s" , p) ;
} while (p) ;
return 0 ;
}

1) Находит следующий токен в строке байта с нулевым завершением, на который указывает str . Символы разделителя идентифицируются нулевой строкой байта, на которую указывает delim .

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

  • Если str ! = NULL str ! = NULL , вызов обрабатывается как первый вызов strtok для этой конкретной строки. Функция выполняет поиск первого символа, который не содержится в delim .
  • Если такого символа не было найдено, то в нем нет токенов, а функция возвращает нулевой указатель.
  • Если такой символ был найден, это будет начало токена . Затем функция выполняет поиск с этой точки для первого символа, который содержится в delim .
    • Если такой символ не найден, str имеет только один токен, а будущие вызовы strtok возвращают нулевой указатель
    • Если такой символ был найден, он заменяется нулевым символом "\0" и указатель на следующий символ сохраняется в статическом месте для последующих вызовов.
  • Затем функция возвращает указатель на начало токена
  • Если str == NULL , вызов обрабатывается как последующие вызовы strtok: функция продолжается от того места, где она осталась в предыдущем вызове. Поведение такое же, как если бы ранее сохраненный указатель передавался как str .

Поведение не определено, если str или delim не является указателем на строку байта с нулевым завершением.

2) То же, что и (1) , за исключением того, что на каждом шаге записывается количество символов, оставшихся для просмотра в str на *strmax и записывает внутреннее состояние токенизатора в *ptr . Повторные вызовы (с нулевой strmax) должны передавать strmax и ptr со значениями, сохраненными предыдущим вызовом. Кроме того, во время выполнения обнаруживаются следующие ошибки и вызывается текущая установленная функция обработчика ограничений , не сохраняя ничего в объекте, на который указывает ptr

  • strmax , delim или ptr - нулевой указатель
  • при не начальном вызове (с нулевой str), *ptr - нулевой указатель
  • при первом вызове *strmax равен нулю или больше, чем RSIZE_MAX
  • поиск конца токена достигает конца исходной строки (как измеряется начальным значением *strmax)), не встречая нулевого терминатора

Поведение не определено, если обе str указывает на массив символов, который не имеет нулевого символа, и strmax указывает на значение, которое больше размера этого массива символов. Как и все связанные с проверкой границ функции, strtok_s гарантированно будет доступен только в том случае, если __STDC_LIB_EXT1__ определяется реализацией, и если пользователь определяет __STDC_WANT_LIB_EXT1__ для целочисленной константы 1 прежде чем включать string.h .

параметры

Возвращаемое значение

Возвращает указатель на начало следующего токена или NULL если больше нет токенов.

Заметка

Эта функция разрушительна: она записывает символы "\0" в элементах строки str . В частности, строковый литерал не может использоваться в качестве первого аргумента strtok .

Каждый вызов strtok изменяет статическую переменную: не является потокобезопасной.

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

Функция strtok_s отличается от функции POSIX strtok_r ее от хранения за пределами токенированной строки и проверяя ограничения времени выполнения.

пример

#define __STDC_WANT_LIB_EXT1__ 1 #include #include int main(void) { char input = "A bird came down the walk"; printf("Parsing the input string "%s"\n", input); char *token = strtok(input, " "); while(token) { puts(token); token = strtok(NULL, " "); } printf("Contents of the input string now: ""); for(size_t n = 0; n < sizeof input; ++n) input[n] ? printf("%c", input[n]) : printf("\\0"); puts("""); #ifdef __STDC_LIB_EXT1__ char str = "A bird came down the walk"; rsize_t strmax = sizeof str; const char *delim = " "; char *next_token; printf("Parsing the input string "%s"\n", str); token = strtok_s(str, &strmax, delim, &next_token); while(token) { puts(token); token = strtok_s(NULL, &strmax, delim, &next_token); } printf("Contents of the input string now: ""); for(size_t n = 0; n < sizeof str; ++n) str[n] ? printf("%c", str[n]) : printf("\\0"); puts("""); #endif }

Возможный выход:

Parsing the input string "A bird came down the walk" A bird came down the walk Contents of the input string now: "A\0bird\0came\0down\0the\0walk\0" Parsing the input string "A bird came down the walk" A bird came down the walk Contents of the input string now: "A\0bird\0came\0down\0the\0walk\0"

  • C11 (ISO / IEC 9899: 2011):
    • 7.24.5.8 Функция strtok (p: 369-370)
    • K.3.7.3.1 Функция strtok_s (p: 620-621)
  • C99 (ISO / IEC 9899: 1999):
    • 7.21.5.8 Функция strtok (p: 332-333)
  • C89 / C90 (ISO / IEC 9899: 1990):
    • 4.11.5.8 Функция strtok
находит первое местоположение любого символа в одной строке, в другой строке
(функция)

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

(C95) (C11)

находит следующий токен в широкой строке
(функция)
Документация C ++ для strtok

Описание

Функция strtok выполняет поиск лексем в строке string . Последовательность вызовов этой функции разбивают строку string на лексемы, которые представляют собой последовательности символов, разделенных символами разделителями.

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

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

Этот конечный маркер автоматически заменяется нулевым символом, и лексема возвращается функцией. После этого, следующие вызовы функции strtok начинаются с этого нулевого символа.

Параметры:

  • string
    Строка для поиска в ней лексем. Содержание этой строки будет изменено, она разбивается на более мелкие строки (лексемы). Данный параметр может содержать нулевой указатель, в этом случае функция продолжает сканирование с того места, где был остановлен предыдущий успешный вызов функции.
  • delim
    Строка, содержащая разделители. Они могут варьироваться от одного вызова к другому вызову функции.

Возвращаемое значение

Указатель на последнюю найденную лексему в строке.
Возвращается пустой указатель, если нет найденных лексем.

Пример: исходный код программы

//пример использования функции strtok #include #include int main () { char str = "Особенности национальной рыбалки - художественный, комедийный фильм."; std::cout << "Разделение строки "" << str << "" на лексемы:n"; char * pch = strtok (str," ,.-"); // во втором параметре указаны разделитель (пробел, запятая, точка, тире) while (pch != NULL) // пока есть лексемы { std::cout << pch << "n"; pch = strtok (NULL, " ,.-"); } return 0; }

Похожие публикации