проблема с вызовом - PullRequest
       23

проблема с вызовом

1 голос
/ 06 апреля 2010

У меня есть функция, использующая strtok, как это

void f1(char *name)
{
...
char *tmp;
tmp = strtok(names, " ,");
while(tmp)
{
...
tmp = strtok(NULL, " ,");
}
...
}

И у меня есть вызов f1 ("abc, def");

Проблема в том, что при первом вызове f1 получает abc, def и во 2-ой звонок получает только abc

Я в замешательстве .. Почему это так?

Ответы [ 4 ]

4 голосов
/ 06 апреля 2010

strtok() изменяет свою входную строку, заменяя разделители на 0; Итак, если ваш код выглядит примерно так:

char parm[] = "abc,def";

f1(parm);
f1(parm);

после первого вызова f1, символ ',' перезаписывается 0, который является ограничителем строки, поэтому второй вызов видит только «abc» как строку.

Обратите внимание: поскольку strtok() изменяет входные данные, вы не хотите передавать ему строковый литерал в качестве аргумента; попытка изменить содержимое строкового литерала вызывает неопределенное поведение.

Безопасная вещь - создать локальную строку внутри f1 и скопировать в нее содержимое имен, а затем передать эту локальную строку в strtok(). Следующее должно работать с C99:

void f1(char *name)
{
  size_t len = strlen(name);
  char localstr[len+1];
  char *tmp;
  strcpy(localstr, name);

  tmp = strtok(localstr, " ,");
  while(tmp)
  {
    ...
    tmp = strtok(NULL, " ,");
  }
}
1 голос
/ 06 апреля 2010

Вы говорите:

И у меня есть вызов f1 ("abc, def");

Этот вызов недопустим - strtok изменяет свой первый параметр, и вы не можете изменять строковые литералы. То, что вы получаете, это неопределенное поведение - все может случиться. Вы хотите:

char a[] = "abc,def";
f1( a );
1 голос
/ 06 апреля 2010

Вы действительно передаете строковый литерал?

f1("abc,def");

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

0 голосов
/ 06 апреля 2010

strtok ставит нулевой терминатор после каждого возвращаемого токена. Это означает, что он уничтожает исходную строку: после ее вызова ваша строка будет завершена после первого токена, что приведет к поведению, которое вы видите.

Чтобы сохранить исходную строку без изменений, вам нужно будет сделать ее копию перед вызовом strtok.

...