вопрос по strtok
От: Mattias  
Дата: 27.05.10 09:40
Оценка: :)
Почему падает вот такой код?

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

и как можно это обойти, если я не хочу каждый раз выделять и уничтожать память под char. Мне нужно разделять строку
достаточно быстро, поскольку это происходит в цикле много раз.
Re: вопрос по strtok
От: Nik_1 Россия  
Дата: 27.05.10 09:55
Оценка: 2 (2) +1
Здравствуйте, Mattias, Вы писали:
M>char test[] = "wert \t\t 32 2 wert";
Re[2]: вопрос по strtok
От: Mattias  
Дата: 27.05.10 10:01
Оценка:
Здравствуйте, Nik_1, Вы писали:

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

M>>char test[] = "wert \t\t 32 2 wert";

Это так, но у меня передается в функцию переменная char*. Кстати а почему это работает, разве не одно и то же?
Re[3]: вопрос по strtok
От: 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";

описан массив с размером по списку инициализации. Обычный массив, делай что хочешь.
With best regards
Pavel Dvorkin
Re[3]: вопрос по strtok
От: Nik_1 Россия  
Дата: 27.05.10 10:25
Оценка:
Здравствуйте, Mattias, Вы писали:
M>Это так, но у меня передается в функцию переменная char*.
учи С
M>Кстати а почему это работает, разве не одно и то же?
в первом случаи ты обьявил указатель на строку, размещенную в сегменте для констант.
А в случаи char test[] обьявляешь массив, который будет создан на стеке и проинициализирован указанной строкой.
Re[3]: вопрос по strtok
От: 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.

Как это сделать?
Re[4]: вопрос по 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 — не так уж мудрено написать код, который не будет менять исходную строку, все равно часто отдельные отрезки копируются куда-то, ...
Re[5]: вопрос по strtok
От: Mattias  
Дата: 27.05.10 12:29
Оценка:
Здравствуйте, 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 — довольно бесполезная, я могу ее использовать только либо используя динамическое выделение , либо заранее зная строку для инициализации массива чаров.

Это так?
Re[6]: вопрос по strtok
От: Centaur Россия  
Дата: 27.05.10 16:11
Оценка: +1
Здравствуйте, Mattias, Вы писали:

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


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

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


Она не просто бесполезная, а вообще вредная. Потому что портит входную строку и, кроме того, имеет внутреннее состояние. То есть, нельзя одновременно разбивать несколько разных строк, хоть в разных потоках, хоть в одном.
Re: вопрос по strtok
От: x905  
Дата: 28.05.10 04:13
Оценка:
Здравствуйте, Mattias, Вы писали:

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


Boost Tokenizer
Re[7]: вопрос по strtok
От: leshy84  
Дата: 03.06.10 06:48
Оценка: +1
Здравствуйте, Centaur, Вы писали:

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


В одном потокое действительно нельзя, но в разных вполне допустимо, т.к. внутреннее состояние она хранит в контексте потока.
Re[4]: вопрос по strtok
От: 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>Как это сделать?


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

Как массивы так и указатели могут располагаться в разных областях памяти — статической, динамической, временной (в стеке), а также в области констант. В зависимости от костантности/неконстантности указателей и адресуемых ими объектов (элементов массива), а также от того в какой области памяти они расположены, набор допустимых операций может варьироваться. Рассмотрим твой исходный пример:
void foo()
{
  char* test = "wert \t\t 32 2 wert";
  strtok(test, " \t\n\r");
}

В этом примере определяется указатель test, указывающий на первый элемент массива символов. Причем указатель и массив расположены в разных областях памяти — указатель в стеке, а массив символов — в статической памяти, доступной только для чтения. В этом и заключается причина ошибки — посредством указателя ты пытаешься модифицировать данные в области памяти, доступной только для чтения. Исправить ошибку можно расположив массив в другой области памяти, например, на стеке:
void foo()
{
  char array[] = "wert \t\t 32 2 wert";
  char* test = array;
  strtok(test, " \t\n\r");
}


Можно было бы вместо стека использовать и динамическую память, но в этом случае возникает вопрос об ответственности за освобождении этой памяти. Решения этого и других вопросов, которые неизбежно возникнут в процессе разработки, лучше начать с чтения книг. Короче говоря, учиться, учиться и учиться (с).
--
Справедливость выше закона. А человечность выше справедливости.
Re[8]: вопрос по strtok
От: 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.

Проще говоря, передаешь ненулевой указатель — начнем парсинг. Передаешь NULL — продолжаем парсинг.
With best regards
Pavel Dvorkin
Re[7]: вопрос по strtok
От: dilmah США  
Дата: 03.06.10 08:23
Оценка:
C>Она не просто бесполезная, а вообще вредная. Потому что портит входную строку и, кроме того, имеет внутреннее состояние. То есть, нельзя одновременно разбивать несколько разных строк, хоть в разных потоках, хоть в одном.

strtok_r есть в posix
Re[9]: вопрос по strtok
От: Centaur Россия  
Дата: 03.06.10 09:13
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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


Ну и? Функция foo начинает токенизацию некоей строки и для каждого токена вызывает функцию bar. Функция bar в процессе своей работы токенизирует какую-то другую строку. При возврате из bar функция foo обнаруживает, что состояние токенизатора испорчено, и всё из-за того, что кто-то сделал функцией (или копрограммой?) то, что по сути должно быть алгоритмом или объектом.
Re: вопрос по strtok
От: Кодт Россия  
Дата: 03.06.10 09:22
Оценка:
Здравствуйте, Mattias, Вы писали:

Велосипед
#define NUL_CHAR '\0' /* для наглядности */

char* tokenize(char** /*inout*/ buffer, const char* delimiters, bool skip_before, bool skip_after)
{
  char* start;
  char* finish;
  char* next;

  assert(buffer && *buffer); /* указатель на существующий буфер */
  assert(delimiters); /* строка */
  assert(*delimiters != NUL_CHAR); /* непустая строка */

  start = *buffer; /* начало токена */
  if(skip_before)
    start += strspn(start,delimiters);

  finish = start + strcspn(start,delimiters); /* конец токена */

  next = finish; /* начало следующего токена */
  if(*finish != NUL_CHAR)
  {
    *finish = NUL_CHAR;
    next = finish+1;
    if(skip_after)
      next += strspn(next,delimiters);
  }

  *buffer = next;
  return start;
}

int main()
{
  const char* line = "мама мыла Раму, мама мыла Кришну!!! :)"; /* в сегменте констант */

  char* temp_line;
  char* tail;
  char* token;

  temp_line = strdup(line); /* создаём копию */
  tail = temp_line;
  while(*tail != NUL_CHAR)
  {
    token = tokenize(&tail, " ,!", true, true);
    printf("«%s» | «%s»\n", token, tail);
  }
  free(temp_line);
  return 0;
}

http://codepad.org/NcRRBRje
Перекуём баги на фичи!
Re[10]: вопрос по strtok
От: Pavel Dvorkin Россия  
Дата: 03.06.10 10:55
Оценка:
Здравствуйте, Centaur, Вы писали:

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


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


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


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


Я и не спорю, что это не лучшим образом сделано. Я просто хотел сказать, что технически невозможно парсить в одном потоке одновременно 2 строки.
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.