strtok возвращает только один токен

Я пишу простую оболочку, которая принимает некоторые стандартные команды, такие как cd и ls в C. Я пытаюсь реализовать функцию, в которой пользователь может вводить ";" между командами, чтобы несколько команд можно было написать в одной строке и выполнять по отдельности. Поэтому, если я ввожу «cd Desktop; ls», оболочка должна перейти на рабочий стол и распечатать то, что находится в каталоге. Проблема в том, что он выполняет только первую команду. Вот мой основной метод:

char input[1024];

while(1)
{
    printf("%s ", prompt);
    fgets(input, 1024, stdin);

    char delims[] = ";";
    char *result = NULL;
    result = strtok( input, delims );

    while( result != NULL )
    {
        printf("%s\n", result);

        char * copy = malloc(strlen(result) + 1); //Create a copy of the input token
        strcpy(copy, result);

        format(copy);

        if(programs)
        {
            handle();
            cleanup(programs);
            programs = NULL;
        }
        free(copy);
        result = strtok( NULL, delims );
        cmdno++;
    }
}

Сначала я пытаюсь разбить ввод на токены на основе ";" а затем передайте токен методу format(), который выглядит так:

int format(char input[])
{
    input = strtok(input, "\n");
    ...
}

Я знаю, что strtok вносит изменения в исходную строку, поэтому я сначала создаю копию токена, прежде чем передавать его в формат. Я правильно делаю??


person vince88    schedule 09.12.2011    source источник


Ответы (2)


Вы не можете смешивать несколько вызовов strtok. Вот что происходит:

  • Вы начинаете разделять input, поэтому strtok принимает к сведению и сохраняет данные внутри себя.
  • You take a break from splitting input
    • You start splitting copy so again strtok takes note, thereby destroying the previous info
  • На данный момент strtok знает только о бизнесе copy и ничего не знает об исходном input.

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


Возможные решения:

  • Используйте strtok_r, если он у вас есть. Это не стандартный C (но это стандартный POSIX). r означает повторный вход
  • Используйте свою собственную функцию разделения (strchr/looping и т.д.)
  • Измените логику своей программы таким образом, чтобы вам не нужно было разбивать copy перед завершением работы с input.

О последнем пункте:

  • Сохраните массив из char * и заполните его strtok, не делая пауз для разделения вложенных токенов. Таким образом, каждый элемент должен быть отдельной командой
  • Когда вы закончите с разделением ";", начните обработку каждого из элементов массива.
person cnicutar    schedule 09.12.2011
comment
Можете ли вы предложить альтернативное решение тогда? - person vince88; 09.12.2011
comment
Я понимаю что ты имеешь ввиду. Если бы я использовал strtok_r, нужно ли было просто добавить _r ко всем экземплярам strtok? Или только в методе формата? - person vince88; 09.12.2011
comment
@vince88 Короткий ответ: каждый раз. Вам нужно изучить справочную страницу для strtok_r и понять параметр lasts. Смотрите ссылку в ответе. - person cnicutar; 09.12.2011
comment
Я изменил логику своей программы, как вы предложили, и это сработало. Спасибо! - person vince88; 09.12.2011

Что насчет этого:

char line[1024];
char *token;
while (1) {
  printf("$ ");
  fgets(line, 1000, stdin);
  token = strtok(line, ";");
  while (token != NULL) {
    printf("%s\n", token);
    token = strtok(NULL, ";");
  }
}
person rendon    schedule 09.12.2011