Функции strtok. Описание функций языка си. Пример: исходный код программы

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

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

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

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

Синтаксис:

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

Результат:

Вывод в консоль:


Описание

Функция 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; } Программы и игры