Функции 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 =
strtok
("The summer soldier, the sunshine patriot"
,
" "
)
;
printf
(p)
;
do
{
p=
strtok
("\0
"
,
", "
)
;
if
(p)
printf
("|% s"
,
p)
;
}
while
(p)
;
return
0
;
}
Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1. Символы, образующие строку, адресуемую параметром str2, представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.
В версии С99 к параметрам str1 и str2 применен квалификатор restrict.
Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok() параметр str1 должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра str1 нужно использовать нулевой указатель. В этом случае полная строка будет модифицироваться при каждом вызове функции.
При каждом обращении к функции strtok() можно использовать различные наборы разделителей лексем.
Функция strtok() предоставляет средство, позволяющее сократить строку до составляющих ее частей. Например, следующая программа разделяет на лексемы строку "One, two, and three".
#include
Результат работы этой программы имеет следующий вид.
One | two | and | three
Обратите внимание, как функция strtok() сначала вызывается с исходной строкой, но в последующих ее вызовах в качестве первого аргумента используется значение NULL. Функция strtok() поддерживает внутренний указатель обрабатываемой строки. Если первый аргумент функции strtok() указывает на строку, внутренний указатель устанавливается в начало этой строки. Если первый аргумент равен значению NULL, функция strtok() продолжает процесс обработки предыдущей строки, начиная с позиции, запомненной на предыдущем шаге, и продвигает внутренний указатель по мере получения очередной лексемы. Таким образом, функция 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 *) . Возвращает длину начала первой строки, в которую входят символы, из которых состоит вторая строка.