Меню
безкоштовно
Головна  /  проблеми / Strtok s c опис. Man strtok_r (3): витяг елементів (токенов) з рядка

Strtok s c опис. Man strtok_r (3): витяг елементів (токенов) з рядка

4 відповіді

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

Важливим наслідком є \u200b\u200bте, що ви не можете використовувати strtok для рядка типу const char * "hello world"; , Так як ви отримаєте порушення доступу при зміні вмісту рядка const char *.

"Хороша річ" в strtok полягає в тому, що насправді вона не копіює рядки, тому вам не потрібно управляти додатковим розподілом пам'яті і т.д. Але якщо ви не зрозумієте вищевикладене, у вас виникнуть проблеми з його використанням.

Приклад. Якщо у вас є "це, є, рядок", послідовні виклики strtok будуть генерувати покажчики наступним чином (значення ^ - це значення, що повертається). Зверніть увагу, що додається "\\ 0", де знайдені токени; це означає, що вихідна рядок змінена:

T his, is, a, string \\ 0 this, is, a, string this \\ 0 is, a, string \\ 0 this ^ this \\ 0 is \\ 0 a, string \\ 0 is ^ this \\ 0 is \\ 0 a \\ Сподіваюся, що це має сенс.

Функція 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 \u003d\u003d NULL && (s \u003d last) \u003d\u003d NULL) return (NULL); / * * Skip (span) leading delimiters (s + \u003d strspn (s, delim), sort of). * / cont: c \u003d * s ++; for (spanp \u003d (char *) delim; (sc \u003d * spanp ++)! \u003d 0;) (if (c \u003d\u003d sc) goto cont;) if (c \u003d\u003d 0) (/ * no non-delimiter characters * / last \u003d NULL; return (NULL);) tok \u003d s - 1; / * * Scan token (scan for delimiters : s + \u003d strcspn (s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. * / for (;;) (c \u003d * s ++; spanp \u003d (char *) delim; do (if ((sc \u003d * spanp ++) \u003d\u003d c) (if (c \u003d\u003d 0) s \u003d NULL; else s [-1] \u003d 0; last \u003d s; return (tok);)) while (sc! \u003d 0);) / * NOTREACHED * /)

поділитися

#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 \u003d strtok ( "Травка зеленіє, сонечко блищить", ""); printf (p); do (p \u003d strtok ( "\\ 0", ","); if (p ) printf ( "|% s", p);) while (p); return 0;)

синтаксис:

#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. Результат розбиття виводиться на консоль.

результат:

Висновок в консоль:


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 \u003d strtok ( "The summer soldier, the sunshine patriot", " " ) ;
printf (p);
do (
p \u003d 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\u003e \u003d 1 || _XOPEN_SOURCE || _POSIX_SOURCE

ОПИС

функція strtok() Розділяє рядок на послідовність нуля або більше непустих токенов. При першому виклику strtok() Анализируемую рядок потрібно вказувати в аргументі str. В кожному наступному виклику, в якому аналізується ця ж рядок, значення str має бути NULL.

В аргументі delim задається набір байт, які вважаються роздільниками токенов в аналізованої рядку. Зухвалий може вказувати різні рядки в delim в наступних викликах при аналізі тієї ж рядки.

кожен виклик strtok() Повертає покажчик на рядок, що завершується , яка містить наступний токен. Цей рядок не включає байт-роздільник. Якщо більше токенов немає, то 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 -\u003e a -\u003e bbb -\u003e cc 2: xxx -\u003e xxx 3: yyy -\u003e yyy

Вихідний код програми

#include #include #include int main (int argc, char * argv) (char * str1, * str2, * token, * subtoken; char * saveptr1, * saveptr2; int j; if (argc! \u003d 4) (fprintf (stderr, "Використання:% s string delim subdelim \\ n ", argv); exit (EXIT_FAILURE);) for (j \u003d 1, str1 \u003d argv;; j ++, str1 \u003d NULL) (token \u003d strtok_r (str1, argv, & saveptr1); if (token \u003d \u003d NULL) break; printf ( "% d:% s \\ n", j, token); for (str2 \u003d token;; str2 \u003d NULL) (subtoken \u003d strtok_r (str2, argv, & saveptr2); if (subtoken \u003d\u003d NULL) break; printf ( "-\u003e% s \\ n", subtoken);)) exit (EXIT_SUCCESS);)

Ще один приклад програми, що використовує strtok(), Можна знайти в getaddrinfo_a(3).