Man strtok_r (3): извлечение элементов (токенов) из строки. Функции для обработки строк Копирование частей строк


Описание

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

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

Синтаксис:

#include
char *strtok(char *str, const char *sep);

Аргументы:

str – указатель на разбиваемую строку.
sep – указатель на строку, содержащую набор символов разделителей.

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

NULL – если строку str невозможно разделить на части.
Указатель на первый символ выделенной части строки.

Описание:

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

«При первом вызове функции strtok указывается начало разделяемой строки (str) и начало строки, содержащей разделители (sep). В начале функция strtok поочередно просматривает символы строки str и ищет символ, не содержащейся в строке разделителей sep. Если в строке str символ конца строки встречен раньше, чем был найден символ не входящий в строку sep, то разделить строку str на части нельзя и возвращается нулевой указатель (NULL). Если такой символ найден, он считается началом первой части строки str.»

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

Если функция strtok вернула не нулевой указатель, можно продолжить разбиение строки str на части. Для продолжения разбиения строки, повторно вызывается функция strtok, но вместо указателя на разбиваемую строку в качестве первого аугмента указывается NULL. В этом случае функция strtok продолжит разбиение с запомненного адреса. Алгоритм разбиения при этом останется тот же.

Пример:

В примере, в строка «test1/test2/test3/test4» разбивается на части по разделителю “/” с помощью функции 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 */ }

поделиться

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

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






2024 © uzbek-seks.ru.