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

Описание

Функция 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; }

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).

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

4 ответа

Две вещи, которые нужно знать о strtok . Как уже упоминалось, он "поддерживает внутреннее состояние". Кроме того, он испортил строку, которую вы ее кормите . По существу, он напишет "\0" , где он найдет маркер, который вы предоставили, и вернет указатель на начало строки. Внутренне он поддерживает расположение последнего токена; и в следующий раз, когда вы его назовете, он начнется оттуда.

Важным следствием является то, что вы не можете использовать strtok для строки типа const char* "hello world"; , так как вы получите нарушение доступа при изменении содержимого строки const char* .

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

Пример. Если у вас есть "это, есть, строка", последовательные вызовы strtok будут генерировать указатели следующим образом (значение ^ - это возвращаемое значение). Обратите внимание, что добавляется "\0" , где найдены токены; это означает, что исходная строка изменена:

T h i s , i s , a , s t r i n g \0 this,is,a,string t h i s \0 i s , a , s t r i n g \0 this ^ t h i s \0 i s \0 a , s t r i n g \0 is ^ t h i s \0 i s \0 a \0 s t r i n g \0 a ^ t h i s \0 i s \0 a \0 s t r i n g \0 string ^

Надеюсь, что это имеет смысл.

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

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

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

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

Функция strtok хранит данные во внутренней статической переменной, которая распределяется между всеми потоками.

Для обеспечения безопасности потоков вы должны использовать strtok_r

Взгляните на static char *last;

Char * strtok(s, delim) register char *s; register const char *delim; { register char *spanp; register int c, sc; char *tok; static char *last; if (s == NULL && (s = last) == NULL) return (NULL); /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). */ cont: c = *s++; for (spanp = (char *)delim; (sc = *spanp++) != 0;) { if (c == sc) goto cont; } if (c == 0) { /* no non-delimiter characters */ last = NULL; return (NULL); } tok = s - 1; /* * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for (;;) { c = *s++; spanp = (char *)delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; last = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ }

поделиться