Strtok s c описание. Описание функций языка си. Исходный код программы

#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; }

Other Alias

strtok

ОБЗОР

#include

char *strtok(char * str , const char * delim );
char *strtok_r(char * str , const char * delim , char ** saveptr );

Требования макроса тестирования свойств для glibc (см. feature_test_macros (7)):

strtok_r (): _SVID_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE

ОПИСАНИЕ

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

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

Каждый вызов strtok () возвращает указатель на строку, завершающуюся null, которая содержит следующий токен. Эта строка не включает байт-разделитель. Если больше токенов нет, то strtok () возвращает NULL.

Последовательность вызовов strtok (), оперирующих одной строкой, поддерживает указатель, который определяет точку, с которой начинается поиск следующего токена. Первый вызов strtok () назначает этому указателю ссылку на первый байт строки. Начало следующего токена определяется поиском вперёд в str следующего байта не разделителя. Если байт найден, то он берётся в качестве начала следующего токена. Если такой байт не найден, то токенов больше нет и strtok () возвращает NULL (для пустой строки или состоящей только из разделителей в этом случае NULL вернётся при первом вызове strtok ()).

Конец каждого токена находится поиском вперёд, длящемся до тех пор, пока не будет найден байт-разделитель или завершающий байт null ("\0"). Если найден байт-разделитель, то он заменяется байтом null для завершения текущего токена, и strtok () сохраняет указатель на следующий байт; этот указатель будет использован в качестве начальной точки при поиске следующего токена. В этом случае strtok () возвращает указатель на начало найденного токена.

Из описания выше следует, что последовательность из двух и более непрерывных байтов-разделителей в просматриваемой строке считается одним разделителем, а байты-разделители в начале или конце строки игнорируются. Другими словами, токены, возвращаемые strtok () - всегда не пустые строки. То есть, например, если есть строка «aaa;;bbb, », то последующие вызовы strtok () с заданными разделителями строк «;, » вернули бы строки «aaa » и «bbb », а затем указатель null.

Функция strtok_r () является реентерабельной версией strtok (). Аргумент saveptr является указателем на переменную char * , которая используется внутри strtok_r () для учёта контекста между последующими вызовами при анализе одной и той же строки.

При первом вызове strtok_r () значение str должно указывать на анализируемую строку, а значение saveptr игнорируется. При последующих вызовах значение str должно быть NULL, а значение saveptr не должно изменяться с момента предыдущего вызова.

Одновременно могут анализироваться разные строки при нескольких запусках strtok_r () с различными аргументами saveptr .

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

Функции strtok () и strtok_r () возвращают указатель на следующий токен или NULL, если больше токенов нет.

АТРИБУТЫ

Описание терминов данного раздела смотрите в attributes (7).
Интерфейс Атрибут Значение
strtok () безвредность в нитях небезопасно (MT-Unsafe race:strtok)
strtok_r () безвредность в нитях безвредно (MT-Safe)

СООТВЕТСТВИЕ СТАНДАРТАМ

strtok () POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD. strtok_r () POSIX.1-2001, POSIX.1-2008.

ДЕФЕКТЫ

Используйте данные функции с осторожностью. Учитывайте, что: * Эти функции изменяют свой первый аргумент. * Эти функции не могут использоваться со строками-константами. * Теряется идентичность байта-разделителя. * При анализе функция strtok () использует статический буфер, поэтому не является безопасной для нитей. Используйте strtok_r () в этом случае.

ПРИМЕР

В программе, представленной далее, используются вложенные циклы, которые вызывают strtok_r () для разделения строки на составляющие её токены. В первом параметре командной строки задаётся анализируемая строка. Во втором параметре задаётся байт(ы)- разделитель, который используется для деления строки на «составные» токены. В третьем параметре указывается байт(ы)- разделитель, который используется для разделения «составных» токенов на подтокены.

Пример результата вывода программы:

$ ./a.out "a/bbb///cc;xxx:yyy:" ":;" "/" 1: a/bbb///cc --> a --> bbb --> cc 2: xxx --> xxx 3: yyy --> yyy

Исходный код программы

#include #include #include int main(int argc, char *argv) { char *str1, *str2, *token, *subtoken; char *saveptr1, *saveptr2; int j; if (argc != 4) { fprintf(stderr, "Использование: %s string delim subdelim\n", argv); exit(EXIT_FAILURE); } for (j = 1, str1 = argv; ; j++, str1 = NULL) { token = strtok_r(str1, argv, &saveptr1); if (token == NULL) break; printf("%d: %s\n", j, token); for (str2 = token; ; str2 = NULL) { subtoken = strtok_r(str2, argv, &saveptr2); if (subtoken == NULL) break; printf(" --> %s\n", subtoken); } } exit(EXIT_SUCCESS); }

Ещё один пример программы, использующей strtok (), можно найти в getaddrinfo_a (3).

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 ;
}

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

В языке программирования 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 *) . Возвращает длину начала первой строки, в которую входят символы, из которых состоит вторая строка.

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