Функції обробки рядків. Man strtok_r (3): вилучення елементів (токенів) з рядка Strtok s c опис

4 відповіді

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

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

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

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

Th 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 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). == sc) goto cont; ) if (c == 0) ( /* no no-delimiter characters */ last = NULL; return (NULL); ) tok = s - 1; : s += strcspn(s, delim), sort of). *)delim; while (sc != 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; }

Мови програмування можуть включати спеціальні функції для роботи з рядками, позбавляючи цим програміста необхідності писати власні функції обробки рядків. Наприклад, часто потрібно визначити довжину рядка, і тому в мовах передбачено функцію, що вимірює її довжину.

У мові програмування 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*). Повертає довжину початку першого рядка, до якого входять символи, з яких складається другий рядок.

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



Подібні публікації