Первое различие в strtok()
и strep()
заключается в способе обработки непрерывных символов разделителя во входной строке.
Обработка непрерывных символов разделителя с помощью strtok()
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
const char* teststr = "aaa-bbb --ccc-ddd"; //Contiguous delimiters between bbb and ccc sub-string
const char* delims = " -"; // delimiters - space and hyphen character
char* token;
char* ptr = strdup(teststr);
if (ptr == NULL) {
fprintf(stderr, "strdup failed");
exit(EXIT_FAILURE);
}
printf ("Original String: %s\n", ptr);
token = strtok (ptr, delims);
while (token != NULL) {
printf("%s\n", token);
token = strtok (NULL, delims);
}
printf ("Original String: %s\n", ptr);
free (ptr);
return 0;
}
Вывод:
# ./example1_strtok
Original String: aaa-bbb --ccc-ddd
aaa
bbb
ccc
ddd
Original String: aaa
В выводе вы можете видеть токены "bbb"
и "ccc"
один за другим.strtok()
не указывает на наличие смежных символов-разделителей .Кроме того, strtok()
изменяет строку ввода .
Обработка непрерывных символов-разделителей с помощью strep()
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
const char* teststr = "aaa-bbb --ccc-ddd"; //Contiguous delimiters between bbb and ccc sub-string
const char* delims = " -"; // delimiters - space and hyphen character
char* token;
char* ptr1;
char* ptr = strdup(teststr);
if (ptr == NULL) {
fprintf(stderr, "strdup failed");
exit(EXIT_FAILURE);
}
ptr1 = ptr;
printf ("Original String: %s\n", ptr);
while ((token = strsep(&ptr1, delims)) != NULL) {
if (*token == '\0') {
token = "<empty>";
}
printf("%s\n", token);
}
if (ptr1 == NULL) // This is just to show that the strep() modifies the pointer passed to it
printf ("ptr1 is NULL\n");
printf ("Original String: %s\n", ptr);
free (ptr);
return 0;
}
Вывод:
# ./example1_strsep
Original String: aaa-bbb --ccc-ddd
aaa
bbb
<empty> <==============
<empty> <==============
ccc
ddd
ptr1 is NULL
Original String: aaa
В выводе вы можете видеть две пустые строки (обозначенные <empty>
) между bbb
и ccc
.Эти две пустые строки предназначены для "--"
между "bbb"
и "ccc"
.Когда strep()
обнаружил символ разделителя ' '
после "bbb"
, он заменил символ разделителя символом '\0'
и вернул "bbb"
.После этого strep()
обнаружил еще один символ-разделитель '-'
.Затем он заменил символ разделителя на '\0'
и вернул пустую строку.То же самое относится и к следующему символу разделителя.
Смежные символы-разделители указываются, когда strsep()
возвращает указатель на нулевой символ (то есть символ со значением '\0'
).
strsep()
изменяет входную строку, а также указатель , адрес которого передан в качестве первого аргумента strsep()
.
Второе отличие состоит в том, что strtok()
полагаетсяна статическую переменную, чтобы отслеживать текущее местоположение разбора в строке.Эта реализация требует, чтобы полностью проанализировал одну строку перед началом второй строки .Но дело обстоит не так с strsep()
.
Вызовом strtok()
, когда другой strtok()
не закончен:
#include <stdio.h>
#include <string.h>
void another_function_callng_strtok(void)
{
char str[] ="ttt -vvvv";
char* delims = " -";
char* token;
printf ("Original String: %s\n", str);
token = strtok (str, delims);
while (token != NULL) {
printf ("%s\n", token);
token = strtok (NULL, delims);
}
printf ("another_function_callng_strtok: I am done.\n");
}
void function_callng_strtok ()
{
char str[] ="aaa --bbb-ccc";
char* delims = " -";
char* token;
printf ("Original String: %s\n", str);
token = strtok (str, delims);
while (token != NULL)
{
printf ("%s\n",token);
another_function_callng_strtok();
token = strtok (NULL, delims);
}
}
int main(void) {
function_callng_strtok();
return 0;
}
Выход:
# ./example2_strtok
Original String: aaa --bbb-ccc
aaa
Original String: ttt -vvvv
ttt
vvvv
another_function_callng_strtok: I am done.
Функция function_callng_strtok()
печатает только токен "aaa"
и не печатает остальные токены входной строки, потому что она вызывает another_function_callng_strtok()
, что, в свою очередь, вызывает strtok()
и устанавливает статический указатель strtok()
на NULL
когда он заканчивается извлечением всех жетонов.Элемент управления возвращается к циклу function_callng_strtok()
while
, strtok()
возвращает NULL
из-за статического указателя, указывающего на NULL
и создающего условие цикла false
и выход из цикла.
Вызовstrsep()
когда еще один strsep()
не закончен:
#include <stdio.h>
#include <string.h>
void another_function_callng_strsep(void)
{
char str[] ="ttt -vvvv";
const char* delims = " -";
char* token;
char* ptr = str;
printf ("Original String: %s\n", str);
while ((token = strsep(&ptr, delims)) != NULL) {
if (*token == '\0') {
token = "<empty>";
}
printf("%s\n", token);
}
printf ("another_function_callng_strsep: I am done.\n");
}
void function_callng_strsep ()
{
char str[] ="aaa --bbb-ccc";
const char* delims = " -";
char* token;
char* ptr = str;
printf ("Original String: %s\n", str);
while ((token = strsep(&ptr, delims)) != NULL) {
if (*token == '\0') {
token = "<empty>";
}
printf("%s\n", token);
another_function_callng_strsep();
}
}
int main(void) {
function_callng_strsep();
return 0;
}
Вывод:
# ./example2_strsep
Original String: aaa --bbb-ccc
aaa
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
<empty>
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
<empty>
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
bbb
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
ccc
Original String: ttt -vvvv
ttt
<empty>
vvvv
another_function_callng_strsep: I am done.
Здесь вы можете увидеть, что вызов strsep()
до полного разбора одной строки не делаетлюбая разница.
Итак, недостатком strtok()
и strsep()
является то, что оба изменяют входную строку, но strsep()
имеет несколько преимуществ по сравнению с strtok()
, как показано выше.
От strsep :
Функция strsep () предназначена для замены функции strtok ().Хотя функция strtok () должна быть предпочтительной по причинам переносимости (она соответствует ISO / IEC 9899: 1990 (`` ISO C90 '')), она не может обрабатывать пустые поля, то есть обнаруживать поля, разделенные двумя соседними символами-разделителями,или использоваться для более чем одной строки одновременно.Функция strsep () впервые появилась в 4.4BSD.
Для справки: