Man strtok_r (3): извлечение элементов (токенов) из строки. Описание функций языка си Strtok c описание
#include
Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1
. Символы, образующие строку, адресуемую параметром str2
, представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.
В версии С99 к параметрам str1
и str2
применен квалификатор restrict .
Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok() параметр str1
должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра str1
нужно использовать нулевой указатель. Этим способом вся строка разбивается на лексемы.
При каждом обращении к функции strtok() можно использовать различные наборы разделителей.
Пример
Эта программа разбивает строку «Травка зеленеет, солнышко блестит» на лексемы, разделителями которых служат пробелы и запятые. В результате получится
Травка|зеленеет|солнышко|блестит
#include
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 */ }
поделитьсяОписание
Функция 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).
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 ;
}