Что такое код strtok


Что такое код strtok

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

Если токен завершается разделителем, то этот символ заменяется символом \0, а указатель на следующий символ сохраняется для следующего вызова strtok() . Разделители могут отличаться при каждом последующем вызове.

Функция strtok_r() является реентрантной версией функции strtok() и вместо статического буфера использует указатель типа char* , предоставленный пользователем. Этот указатель, передаваемый в параметре ptrptr , должен быть одним и тем же при обработке одной и той же строки.

НАЙДЕННЫЕ ОШИБКИ

Эти функции изменяют свой первый аргумент.

Эти функции нельзя использовать со строковыми константами.

Информация о символах-разделителях теряется.

Функция strtok () использует статический буфер при обработке строки, поэтому её небезопасно использовать в программах со множеством процессов, работающих с одной областью памяти. Если Вам подходит strtok_r (), то используйте эту функцию.

Функция strtok

Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1 . Символы, образующие строку, адресуемую параметром str2 , представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.

В версии С99 к параметрам str1 и str2 применен квалификатор restrict .

Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok() параметр str1 должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра str1 нужно использовать нулевой указатель. Этим способом вся строка разбивается на лексемы.

При каждом обращении к функции strtok() можно использовать различные наборы разделителей.

Пример

Эта программа разбивает строку «Травка зеленеет, солнышко блестит» на лексемы, разделителями которых служат пробелы и запятые. В результате получится

strtok, _fstrtok

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-версией рассматриваемой функции.

Что такое код strtok

Почему падает вот такой код?

char* test = «wert \t\t 32 2 wert»;
strtok(test, » \t\n\r»);

и как можно это обойти, если я не хочу каждый раз выделять и уничтожать память под char. Мне нужно разделять строку
достаточно быстро, поскольку это происходит в цикле много раз.

От: Nik_1
Дата: 27.05.10 09:55
Оценка: 2 (2) +1
От: Mattias
Дата: 27.05.10 10:01
Оценка:

Здравствуйте, Nik_1, Вы писали:

N_>Здравствуйте, Mattias, Вы писали:
M>>char test[] = «wert \t\t 32 2 wert»;

Это так, но у меня передается в функцию переменная char*. Кстати а почему это работает, разве не одно и то же?

От: Pavel Dvorkin
Дата: 27.05.10 10:06
Оценка: 1 (1)

Здравствуйте, Mattias, Вы писали:

M>Это так, но у меня передается в функцию переменная char*.

На здоровье. Никаких проблем ч передачей тудв test не будет.

>Кстати а почему это работает, разве не одно и то же?

char* test = «wert \t\t 32 2 wert»;

описан указатель на строку. Строка хранится в R/O памяти, поэтому strtok в ней нули вставлять не может.

char test[] = «wert \t\t 32 2 wert»;

описан массив с размером по списку инициализации. Обычный массив, делай что хочешь.

От: Nik_1
Дата: 27.05.10 10:25
Оценка:
От: Mattias
Дата: 27.05.10 12:03
Оценка:

Здравствуйте, Mattias, Вы писали:

M>Здравствуйте, Nik_1, Вы писали:

N_>>Здравствуйте, Mattias, Вы писали:
M>>>char test[] = «wert \t\t 32 2 wert»;

M>Это так, но у меня передается в функцию переменная char*. Кстати а почему это работает, разве не одно и то же?

И все таки я не понял. Вот есть код:

char* test = . ; // код который возвращает char*

далее я хочу разбить test на токены с помощью strtok.

Как это сделать?

От: ilnar
Дата: 27.05.10 12:09
Оценка:

Здравствуйте, Mattias, Вы писали:

M>Здравствуйте, Mattias, Вы писали:

M>>Здравствуйте, Nik_1, Вы писали:

N_>>>Здравствуйте, Mattias, Вы писали:
M>>>>char test[] = «wert \t\t 32 2 wert»;

M>>Это так, но у меня передается в функцию переменная char*. Кстати а почему это работает, разве не одно и то же?

M>И все таки я не понял. Вот есть код:

M>char* test = . ; // код который возвращает char*

M>далее я хочу разбить test на токены с помощью strtok.

M>Как это сделать?

помни, что strtok меняет переданную строку, вставляя 0 символы в нужных местах
поэтому надо передавать строку, в которую можно писать
или же отказаться от использования strtok — не так уж мудрено написать код, который не будет менять исходную строку, все равно часто отдельные отрезки копируются куда-то, .

От: Mattias
Дата: 27.05.10 12:29
Оценка:
Илон Маск рекомендует:  Описания кодов состояния rfc 2068

Здравствуйте, ilnar, Вы писали:

I>Здравствуйте, Mattias, Вы писали:

M>>Здравствуйте, Mattias, Вы писали:

M>>>Здравствуйте, Nik_1, Вы писали:

N_>>>>Здравствуйте, Mattias, Вы писали:
M>>>>>char test[] = «wert \t\t 32 2 wert»;

M>>>Это так, но у меня передается в функцию переменная char*. Кстати а почему это работает, разве не одно и то же?

M>>И все таки я не понял. Вот есть код:

M>>char* test = . ; // код который возвращает char*

M>>далее я хочу разбить test на токены с помощью strtok.

M>>Как это сделать?

I>помни, что strtok меняет переданную строку, вставляя 0 символы в нужных местах
I>поэтому надо передавать строку, в которую можно писать
I>или же отказаться от использования strtok — не так уж мудрено написать код, который не будет менять исходную строку, все равно часто отдельные отрезки копируются куда-то, .

Хорошо. Тогда следующий вопрос, могу ли я создать char[] из char* не используя динамического выделения памяти.

Если нет , то мне кажется функция strtok — довольно бесполезная, я могу ее использовать только либо используя динамическое выделение , либо заранее зная строку для инициализации массива чаров.

От: Centaur
Дата: 27.05.10 16:11
Оценка: +1

Здравствуйте, Mattias, Вы писали:

M>Хорошо. Тогда следующий вопрос, могу ли я создать char[] из char* не используя динамического выделения памяти.

Нет, конечно. Однако, без динамического выделения памяти вообще почти ничего полезного нельзя сделать — кроме, разве что, нескольких безопастностных уязвимостей.

M>Если нет , то мне кажется функция strtok — довольно бесполезная, я могу ее использовать только либо используя динамическое выделение , либо заранее зная строку для инициализации массива чаров.

Она не просто бесполезная, а вообще вредная. Потому что портит входную строку и, кроме того, имеет внутреннее состояние. То есть, нельзя одновременно разбивать несколько разных строк, хоть в разных потоках, хоть в одном.

От: x905
Дата: 28.05.10 04:13
Оценка:

Здравствуйте, Mattias, Вы писали:

M> Мне нужно разделять строку

От: leshy84
Дата: 03.06.10 06:48
Оценка: +1

Здравствуйте, Centaur, Вы писали:

C>Она не просто бесполезная, а вообще вредная. Потому что портит входную строку и, кроме того, имеет внутреннее состояние. То есть, нельзя одновременно разбивать несколько разных строк, хоть в разных потоках, хоть в одном.

В одном потокое действительно нельзя, но в разных вполне допустимо, т.к. внутреннее состояние она хранит в контексте потока.

От: rg45
Дата: 03.06.10 08:07
Оценка:

Здравствуйте, Mattias, Вы писали:

N_>>>Здравствуйте, Mattias, Вы писали:
M>>>>char test[] = «wert \t\t 32 2 wert»;

M>>Это так, но у меня передается в функцию переменная char*. Кстати а почему это работает, разве не одно и то же?

M>И все таки я не понял. Вот есть код:

M>char* test = . ; // код который возвращает char*

M>далее я хочу разбить test на токены с помощью strtok.

M>Как это сделать?

Тебе тут надавали кучу разных советов и, ИМХО, еще сильнее сбили тебя с толку. Все что тебе нужно на данном этапе — это понять разницу между массивом и указателем — это не одно и то же. Лучший способ разобраться в предмете — почитать учебник. если в двух словах, то массив — это последовательность однотипных объектов, расположенных в памяти друг за другом. Указатель — это переменная (или константа), в которой записан адрес какого-либо объекта. С помощью указателей можно ссылаться как на одиночные объекты, так и на элементы массивов. К указателям применимы операции сравнения, инкремента, декремента, сложения и вычитания (так называемая арифметика указателей). При этом автоматически считается, что указатель указывает на элемент массива, применение этих операций к указателю на одиночный объект приводит к неопределенному поведению программы. Массивы могут автоматически (неявно) преобразовываться в указатели, при этом образуется указатель, указывающий на первый элемент массива, после чего к указателю можно применять арифметические операции и тем самым осуществлять навигацию по элементам массива.

Как массивы так и указатели могут располагаться в разных областях памяти — статической, динамической, временной (в стеке), а также в области констант. В зависимости от костантности/неконстантности указателей и адресуемых ими объектов (элементов массива), а также от того в какой области памяти они расположены, набор допустимых операций может варьироваться. Рассмотрим твой исходный пример:

В этом примере определяется указатель test, указывающий на первый элемент массива символов. Причем указатель и массив расположены в разных областях памяти — указатель в стеке, а массив символов — в статической памяти, доступной только для чтения. В этом и заключается причина ошибки — посредством указателя ты пытаешься модифицировать данные в области памяти, доступной только для чтения. Исправить ошибку можно расположив массив в другой области памяти, например, на стеке:


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

От: Pavel Dvorkin
Дата: 03.06.10 08:10
Оценка:

Здравствуйте, leshy84, Вы писали:

L>В одном потокое действительно нельзя, но в разных вполне допустимо, т.к. внутреннее состояние она хранит в контексте потока.

А в одном потоке — просто не удастся.

On the first call to strtok, the function skips leading delimiters and returns a pointer to the first token in strToken, terminating the token with a null character. More tokens can be broken out of the remainder of strToken by a series of calls to strtok. Each call to strtokmodifies strToken by inserting a null character after the token returned by that call. To read the next token from strToken, call strtok with a NULL value for the strToken argument. The NULL strToken argument causes strtok to search for the next token in the modified strToken. The strDelimit argument can take any value from one call to the next so that the set of delimiters may vary.

Илон Маск рекомендует:  Что такое код cabs

Проще говоря, передаешь ненулевой указатель — начнем парсинг. Передаешь NULL — продолжаем парсинг.

От: dilmah
Дата: 03.06.10 08:23
Оценка:

C>Она не просто бесполезная, а вообще вредная. Потому что портит входную строку и, кроме того, имеет внутреннее состояние. То есть, нельзя одновременно разбивать несколько разных строк, хоть в разных потоках, хоть в одном.

strtok_r есть в posix

От: Centaur
Дата: 03.06.10 09:13
Оценка:

Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А в одном потоке — просто не удастся.

PD>передаешь ненулевой указатель — начнем парсинг. Передаешь NULL — продолжаем парсинг.

Ну и? Функция foo начинает токенизацию некоей строки и для каждого токена вызывает функцию bar. Функция bar в процессе своей работы токенизирует какую-то другую строку. При возврате из bar функция foo обнаруживает, что состояние токенизатора испорчено, и всё из-за того, что кто-то сделал функцией (или копрограммой?) то, что по сути должно быть алгоритмом или объектом.

strtok

Комментарии

Функция strtok выделяет очередную часть строки, на которую указывает аргумент str, отделенную одним из символов разделителей указанных в строке, на которую указывает аргумент sep. Последовательный вызов функции strtok приводит к разбиению строки str на части (лексемы).

При первом вызове функции strtok указывается начало разделяемой строки (str) и начало строки, содержащей разделители (sep). Функция strtok поочередно просматривает символы строки str и ищет первое вхождение символа, не содержащегося в строке разделителей sep. Если символ конца строки встречен раньше чем был найден символ не входящий в строку sep, то разделить строку str на части нельзя и возвращается нулевой указатель (NULL). Если такой символ найден, он считается началом первой части строки str.

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

Если функция strtok вернула не нулевой указатель, можно продолжить разбиение строки str на части. Для продолжения разбиения строки, повторно вызывается функция strtok, но вместо указателя на разбиваемую строку в качестве первого аугмента указывается NULL. В этом случае функция strtok продолжит разбиение с запомненного адреса. Алгоритм разбиения при этом останется тот же.

Описание функций C (Си) / C++ — strtok

Описание функций C (Си) / C++ — strtok

#include требуется только для объявления
функции

char *strtor(string1,string2);
находит символ в string1
char *string1; строка, содержащая символы
char *string2; множество символов-ограничителей

Функция strtok читает строку string1 как множество нуль или
более знаков, служащих в качестве ограничителей для символов в
string1. Символы в string1 могут отделяться одним или более огра-

ничителем от string2. Символы в string1 разрываются столько раз,
сколько вызывается strtok. При первом вызове strtok для заданной
строки string1, strtok находит первый символ в string1, пропуская
предыдущие ограничители. Указатель возвращается на первый знак.
Для того, чтобы прочитать следующий символ из string1, функция
strtok вызывается вместе с NULL значением для аргумента string1.
Аргумент NULL строки string1 вызывает strtok для поиска следующе-
го знака в предыдущей строке символов. Множество ограничителей
может быть различным от вызова к вызову, так как string2 может
принимать любые значения.
Замечание. String1 можно модифицировать вызовами strtok,
так как после вызова strtok в string1 вставляется нулевое значе-
ние (‘).

При вызове strtok первый раз, она возвращает указатель на
первый символ в string1. При последующих вызовах в этой же самой
строке символов, strtok возвращает указатель на следующий символ
в строке. Указатель NULL возвращается, когда нет больше символов.
Все символы оканчиваются нулем.
См. также strcspn, strspn.

char *string = «a string, of , ,tokens»;
.
.
.
/* в следующем цикле собираются символы (отделенные пробе-
лами или запятыми) из строки до тех пор, пока в ней ничего не ос-
танется */
token = strtok(string,»,»);

while (token !=NULL) <
/* вставляет код для обработки символа в цикле */
.
.
.
token = strtok(NULL,»,»);
/* берет следующий символ */
>

/* возвращаемыми символами являются «a»,»string», «of»,
«tokens». Следующий вызов strtok возвратит NULL и цикл завершает-
ся */

Функция strtok

Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1 . Символы, образующие строку, адресуемую параметром str2 , представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.

В версии С99 к параметрам str1 и str2 применен квалификатор restrict .

Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok() параметр str1 должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра str1 нужно использовать нулевой указатель. Этим способом вся строка разбивается на лексемы.

При каждом обращении к функции strtok() можно использовать различные наборы разделителей.

Пример

Эта программа разбивает строку «Травка зеленеет, солнышко блестит» на лексемы, разделителями которых служат пробелы и запятые. В результате получится

C Language Tokenisation: strtok (), strtok_r () и strtok_s ()

пример

Функция strtok разбивает строку на меньшие строки или жетоны, используя набор разделителей.

Строка разделителей может содержать один или несколько разделителей, и с каждым вызовом strtok могут использоваться разные строки разделителя.

Илон Маск рекомендует:  Псевдокласс only-child в CSS

Вызовы в strtok для продолжения токенизации одной и той же исходной строки не должны снова передавать исходную строку, а вместо этого передавать NULL в качестве первого аргумента. Если же исходная строка передается затем первый маркер вместо этого будет повторно лексемы. То есть, учитывая те же разделители, strtok просто вернет первый токен снова.

Обратите внимание: поскольку strtok не выделяет новую память для токенов, она изменяет исходную строку . То есть в приведенном выше примере строка src будет обрабатываться для создания маркеров, на которые ссылается указатель, возвращаемый вызовами strtok . Это означает, что исходная строка не может быть const (поэтому она не может быть строковым литералом). Это также означает, что личность разделительного байта теряется (т. Е. В примере «,» и «!» Эффективно удаляются из исходной строки, и вы не можете определить, какой символ разделителя совпадают).

Заметим также, что несколько последовательных разделителей в исходной строке рассматриваются как один; в этом примере вторая запятая игнорируется.

strtok является ни потокобезопасным, ни повторным, поскольку он использует статический буфер при разборе. Это означает, что если функция вызывает strtok , никакая функция, которую она вызывает при использовании strtok также может использовать strtok , и она не может быть вызвана любой функцией, которая сама использует strtok .

Пример, демонстрирующий проблемы, вызванные тем, что strtok не является повторным, выглядит следующим образом:

Ожидаемая операция является то , что наружный do while во «1.2» «3.5» «4.2» strtok do while цикла должно создать три маркера , состоящие из каждой строки десятичных чисел ( «1.2» , «3.5» , «4.2» ), для каждого из которых strtok предусматривает внутренний цикл должен разделить его на отдельные ( «1» , «2» , «3» , «5» , «4» , «2» ).

Однако, поскольку strtok не является повторным, этого не происходит. Вместо этого первый strtok правильно создает токен «1,2 \ 0», а внутренний цикл правильно создает токены «1» и «2» . Но тогда strtok во внешнем цикле находится в конце строки, используемой внутренним циклом, и немедленно возвращает NULL. Вторая и третья подстроки массива src вообще не анализируются.

Стандартные библиотеки C не содержат потокобезопасную или повторную версию, но некоторые другие, например POSIX ‘ strtok_r . Обратите внимание, что в MSVC эквивалент strtok strtok_s является потокобезопасным.

C11 имеет необязательную часть, приложение K, которая предлагает поточно-безопасную и повторную версию с именем strtok_s . Вы можете протестировать эту функцию с помощью __STDC_LIB_EXT1__ . Эта дополнительная часть не поддерживается широко.

Функция strtok_s отличается от функции POSIX strtok_r ее от хранения за пределами токенированной строки и проверяя ограничения времени выполнения. Однако при правильно написанных программах strtok_s и strtok_r ведут себя одинаково.

Использование strtok_s с примером теперь дает правильный ответ, например:

Что такое код strtok

Функция strtok() возвращает указатель на следующую лексему в строке, адресуемой параметром str1. Символы, образующие строку, адресуемую параметром str2, представляют собой разделители, которые определяют лексему. При отсутствии лексемы, подлежащей возврату, возвращается нулевой указатель.

В версии С99 к параметрам str1 и str2 применен квалификатор restrict.

Чтобы разделить некоторую строку на лексемы, при первом вызове функции strtok() параметр str1 должен указывать на начало этой строки. При последующих вызовах функции в качестве параметра str1 нужно использовать нулевой указатель. В этом случае полная строка будет модифицироваться при каждом вызове функции.

При каждом обращении к функции strtok() можно использовать различные наборы разделителей лексем.

Совет программисту

Функция strtok() предоставляет средство, позволяющее сократить строку до составляющих ее частей. Например, следующая программа разделяет на лексемы строку «One, two, and three».

Результат работы этой программы имеет следующий вид.

Обратите внимание, как функция strtok() сначала вызывается с исходной строкой, но в последующих ее вызовах в качестве первого аргумента используется значение NULL. Функция strtok() поддерживает внутренний указатель обрабатываемой строки. Если первый аргумент функции strtok() указывает на строку, внутренний указатель устанавливается в начало этой строки. Если первый аргумент равен значению NULL, функция strtok() продолжает процесс обработки предыдущей строки, начиная с позиции, запомненной на предыдущем шаге, и продвигает внутренний указатель по мере получения очередной лексемы. Таким образом, функция strtok() «проходит» всю строку. Также обратите внимание на то, как изменяется строка, задающая разделители, при первом и последующих вызовах функции. При каждом вызове разделители могут определяться по-разному.

Как работает функция strtok в C?

Я нашел эту примерную программу, которая объясняет функцию strtok :

Однако я не вижу, как это можно работать.

Как возможно, что pch = strtok (NULL, » ,.-«); возвращает новый токен. Я имею в виду, мы вызываем strtok с NULL . Это не имеет большого значения для меня.

Две вещи, которые нужно знать о strtok . Как уже упоминалось, он «поддерживает внутреннее состояние». Кроме того, он испортил строку, которую вы ее кормите. По существу, он напишет ‘\0’ , где он найдет маркер, который вы предоставили, и вернет указатель на начало строки. Внутренне он поддерживает расположение последнего токена; и в следующий раз, когда вы его назовете, он начнется оттуда.

Важным следствием является то, что вы не можете использовать strtok для строки типа const char* «hello world»; , так как вы получите нарушение доступа при изменении содержимого строки const char* .

«Хорошая вещь» в strtok заключается в том, что на самом деле она не копирует строки, поэтому вам не нужно управлять дополнительным распределением памяти и т.д. Но если вы не поймете вышеизложенное, у вас возникнут проблемы с его использованием.

Пример. Если у вас есть «это, есть, строка», последовательные вызовы strtok будут генерировать указатели следующим образом (значение ^ — это возвращаемое значение). Обратите внимание, что добавляется ‘\0’ , где найдены токены; это означает, что исходная строка изменена:

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL