Пытаясь понять strtok - PullRequest
       5

Пытаясь понять strtok

4 голосов
/ 14 января 2011

Рассмотрим следующий фрагмент, который использует strtok для разбиения строки Мэдди.

char* str = (char*) malloc(sizeof("Madddy"));
strcpy(str,"Madddy");

char* tmp = strtok(str,"d");
std::cout<<tmp;

do
{
    std::cout<<tmp;
    tmp=strtok(NULL, "dddy");
}while(tmp!=NULL);

Работает нормально, вывод Ма. Но, изменив strtok следующим образом,

tmp=strtok(NULL, "ay");

Выход становится Madd. Так как же работает strtok? У меня есть этот вопрос, потому что я ожидал, что strtok будет принимать каждый символ, который находится в строке разделителя, который будет считаться разделителем. Но в некоторых случаях это происходит именно так, а в некоторых случаях дает неожиданные результаты. Может ли кто-нибудь помочь мне понять это?

Ответы [ 6 ]

10 голосов
/ 14 января 2011

"Пытаюсь понять strtok" Удачи!

В любом случае, мы находимся в 2011 году. Правильный токен:

std::string str("abc:def");
char split_char = ':';
std::istringstream split(str);
std::vector<std::string> token;

for (std::string each; std::getline(split, each, split_char); token.push_back(each));

: D

3 голосов
/ 14 января 2011

Фред Флинтстоун, вероятно, использовал strtok(). Он предшествует многопоточным средам и изменяет (изменяет) исходную строку.

Когда вызывается с NULL для первого параметра, он продолжает анализ последней строки. Эта функция была удобной, но немного необычной даже в свое время.

2 голосов
/ 14 января 2011

На самом деле ваш код неверен, неудивительно, что вы получите неожиданные результаты:

char* str = (char*) malloc(sizeof("Madddy"));

должно быть

char* str = (char*) malloc(strlen("Madddy") + 1);
1 голос
/ 14 января 2011

Кажется, вы забыли, что вы впервые вызывали strtok (из цикла) через разделитель "d".

strtok работает нормально. У вас должна быть ссылка здесь .

Для второго примера (strtok("ay")):

Сначала вы вызываете strtok (str, "d"). Он будет искать первую букву "d" и разделять вашу строку. В частности, он устанавливает tmp = "Ma" и str = "ddy" (отбрасывая первые "d").

Затем вы называете strtok (str, "ay"). Он будет искать «a» в str, но поскольку ваша строка теперь только «ddy», совпадение не происходит. Тогда он будет искать «у». Так что str = "dd" и tmp = "".

На нем напечатано "Мэдд", как вы видели.

0 голосов
/ 14 января 2011

Поскольку вы изменили свой тег на C, а не на C ++, я переписал вашу функцию для использования printf, чтобы вы могли видеть, что происходит.Хоанг прав.Вы видите правильный вывод, но я думаю, что вы печатаете все в одной строке, поэтому вы запутались в выводе.Посмотрите на ответ Хоанга, который объясняет, что происходит правильно.Также, как отмечали другие, strtok уничтожает входную строку, поэтому вы должны быть осторожны с этим - и это не безопасно для потоков.Но если вам нужен быстрый грязный токенизатор, он работает.Кроме того, я изменил код, чтобы правильно использовать strlen, а не sizeof, как правильно указал Андерс.

Вот ваш код, модифицированный так, чтобы он был более похож на C:

char* str = (char*) malloc(strlen("Madddy") + 1);
strcpy(str,"Madddy");

char* tmp = strtok(str,"d");
printf ("first token: %s\n", tmp);

do
{
    tmp=strtok(NULL, "ay");
    if (tmp != NULL ) {
       printf ("next token: %s\n", tmp);
    }
} while(tmp != NULL);
0 голосов
/ 14 января 2011

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

Чтобы процитировать ответ, данный мне оттуда:

Общая ловушка с strtok() Функция предполагает, что проанализированный Строка остается без изменений, пока она фактически заменяет разделитель символ с '\0'.

Кроме того, strtok() используется при создании последующие вызовы до вся строка маркируется. Немного магазин библиотечных реализаций strtok() внутренний статус в глобальная переменная, которая может вызвать некоторые неприятные сюрпризы, если strtok() вызывается из нескольких потоков на в то же время.

Поскольку вы отметили свой вопрос C ++, используйте что-то еще! Если вы хотите использовать C, я бы посоветовал реализовать собственный токенизатор, который работает безопасным образом.

...