Использование strtok на языке C

У меня проблема с использованием strtok в C. Я получаю пользовательский ввод из командной строки, используя fgets, и я хочу разметить его с помощью канала ("|") в качестве разделителя и поместить результат в переменную с двойным указателем. Вот мой код:

char** argv;
char *token;
token = strtok(userInput, "|");
while(token != NULL){
  *(argv++) = token;
   token = strtok(NULL, "|");
}

*argv = '\0';

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

while(*argv!= NULL)
{
   if((strcmp(*argv, "|") == 0){
   count = count + 1;
   }
   argv++;
}
printf("%d pipes", count);

Но это не работает. char** argv ничего не содержит. Выполнение кода останавливается и возвращается -1. Когда я пытаюсь напечатать argv, argv не содержит значений.

Любые идеи, пожалуйста? Спасибо.

Редактировать:

Я хочу сделать это

userInput = "abc|cde";

После использования стрток. Я хочу иметь **argv

**argv = "abc";

person mkab    schedule 26.11.2011    source источник
comment
Но это не работает. Что именно происходит?   -  person Dennis    schedule 26.11.2011
comment
Когда вы говорите, что это не работает, какую ошибку вы получаете?   -  person Jonathan M    schedule 26.11.2011
comment
Что вы имеете в виду под не работает? Код делает именно то, что вы ему говорите. Это может отличаться от того, что вы ожидаете, но об этом невозможно догадаться, если вы не хотите нам об этом говорить.   -  person Kerrek SB    schedule 26.11.2011
comment
Извините, если я не был ясен. Я имел в виду, что char** argv ничего не содержит. Выполнение кода останавливается и возвращается -1. Когда я пытаюсь напечатать argv, argv не содержит значений.   -  person mkab    schedule 26.11.2011


Ответы (4)


Одна проблема заключается в том, что вы, похоже, не инициализируете argv. Вам нужно выделить достаточно памяти, чтобы вместить столько char *, сколько необходимо. В противном случае вы пишете в какой-то случайный блок памяти. (Вы просто не показали нам соответствующий код?)

Другая проблема заключается в том, что вы на самом деле изменяете argv, поэтому в конце этого цикла он указывает на один после последнего токена (и затем вы устанавливаете *argv на NULL); но ваш код подтверждения предполагает, что он указывает на первый токен, и начинается с подтверждения того, что *argv не NULL. (Просто вы не показали нам соответствующий код?) Отредактировано для добавления: Из вашего комментария выше я вижу, что «argv не содержит значений». Я почти уверен, что причина в это.

Кстати, вы путаете '\0' (нулевой байт) с NULL (нулевой указатель). Технически это работает правильно: '\0' повышается до 0, 0 преобразуется в NULL, но меня немного беспокоит, что вы их путаете, поскольку концептуально они совершенно разные. Вы должны написать *argv = NULL, а не *argv = '\0', хотя бы для ясности.

person ruakh    schedule 26.11.2011

ваш код токенизации работает следующим образом: если

userInput = "a|b|c"

тогда

argv = { "a", "b", "c" }

вы могли ожидать, что

argv = {"a","|","b","|","c"}

Ваш код для подсчета труб должен быть:

while(*argv != NULL)
{
   count = count + 1;
   argv++;
}
printf("%d pipes", count-1);

я думаю, это сработает

person anshul410    schedule 26.11.2011
comment
Это немного близко к тому, что я хочу. На самом деле я хочу: если у меня есть userInput, например {a b | c d NULL}, я хочу char **argv = {"a", "b", NULL} - person mkab; 26.11.2011
comment
Вы говорите, что вам просто нужна подстрока перед первым '|' разделитель. ?? - person anshul410; 26.11.2011
comment
Да точно! Я хочу использовать строку до и после первого разделителя. Так, например, перед каналом у меня может быть ls -l. Поэтому я хочу поместить этот ls -l в **argv и выполнить его с помощью execvp. - person mkab; 26.11.2011

я использую этот формат для поиска 300x400. ищите «x», чтобы избавиться от x и использовать обе стороны, 300 и 400 . это работает для меня.

 char *tok1, *tok2, *saveptr;

 tok1 = strtok_r(argv, "x", &saveptr);
 tok2 = strtok_r(NULL, "x", &saveptr);

 printf("this tok1 %s this is tok2 %s\n", tok1, tok2);

используя функцию strtok_r

person uxserx-bw    schedule 23.12.2013

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

здесь возникает проблема: *(argv++) = токен

argv (указатель на char*) увеличивается, когда вы добавляете указатель токена в массив argv (я предполагаю, что вы правильно его инициализировали). Поэтому, когда вы используете вторую часть кода для получения результата, argv уже указывает на последний элемент, в вашем случае '\0', который не будет выводить.

И вы смешиваете «\ 0» с NULL, хотя они оба грамматически правильны, но в вашем случае лучше использовать NULL, потому что это означает указатель, но «\ 0» означает нулевое завершение в C-строке

Вы можете изменить свой код на следующий:

/* Init argv array */
char** argv;
size_t argc=0;  // token count
char *token;
token = strtok(userInput, "|");
while(token != NULL){
   argv[argc++] = token;
   token = strtok(NULL, "|");
}
argv[argc] = NULL;  // the last element of argv array is a NULL pointer

/* get result from argv */

while(*argv!= NULL)
{
   if((strcmp(*argv, "|") == 0){
   count = count + 1;
   }
   argv++;
}
printf("%d pipes", count);
person wacky6    schedule 23.12.2013