2017-01-12 18 views
1

Я понимаю, что заголовок сбивает с толку, не мог придумать более ясный способ его слова. В принципе, я вызываю цикл strtok внутри цикла strtok, но когда внутренняя функция strtok возвращается из runCommand, мой первый цикл strtok останавливается. Он просто выходит из цикла, даже когда есть другие аргументы после первой точки с запятой. Когда я не вызываю runCommand(), он работает так, как ожидалось, и анализирует все мои команды, разделенные точкой с запятой.Strtok внутри strtok не работает с копией оригинального токена - C

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

void parseCommand(char *userLine) 
{ 
    if(strchr(userLine, ';')) 
    { 
    // Get first token 
    token = strtok(userLine, ";"); 
    // Loop through all tokens 
    while(token != NULL) 
    { 
     // Make a copy 
     char *copy = malloc(strlen(token) + 1); 
     strcpy(copy, token); 
     runCommand(copy); 
     free(copy); 
     printf("process returned!\n"); 
     token = strtok(NULL, ";"); 
    } 
    } 
} 
void runCommand(char *token) 
{ 
    char *args[20]; 
    char **command = args; 
    //Tokenize each command based on space 

    char *temp = strtok(token, " \n"); 
    while (temp != NULL) 
    { 
    *command++ = temp; 
    temp = strtok(NULL, " \n"); 
    } 
    *command = NULL; 
// code for fork and execvp here 
} 

Может кто-то объяснить, почему RunCommand завинчивания до разбора моей первой функции в? Я ДЕЙСТВИТЕЛЬНО не понимаю, почему он не работает с копией моего оригинального токена. Наверное, просто, но я слишком долго смотрел на него?

+3

«Я вызываю петлю strtok внутри петли strtok» - не может этого сделать. Конструкция 'strtok' выглядит отстойной. – user2357112

+0

Да, вы не можете использовать 'strtok'« рекурсивно »так, как только вы передадите новый аргумент, отличный от' NULL', он полностью забывает о своем предыдущем аргументе. Вы должны обработать свои жетоны шириной - сначала, а не глубину - сначала. –

+0

См. Документацию по [Tokenization: 'strtok()', 'strtok_r()' и 'strtok_s()'] (http://stackoverflow.com/documentation/c/1990/strings/2557/tokenisation-strtok-strtok- г-и-strtok-е # т = 20170113015701136593). –

ответ

5

Функция strtok не является реентерабельной. Он запоминает текущее состояние, поэтому вы принимаете NULL для повторных вызовов без segfault.

Рассмотрите возможность использования strtok_s или strtok_r (в зависимости от реализации), который позволяет вызывающему абоненту сохранять состояние. Они могут использоваться вложенным образом.

+0

'strtok_r' не является стандартным, рекомендуется использовать' strtok_s'. – Olaf

+0

СПАСИБО !! В следующий раз я присмотрюсь к документации. – Tee

+0

@Olaf: Если вы работаете в Windows, 'strtok_s()' является тем, который будет использоваться, потому что он доступен. Если вы работаете в Unix, 'strtok_s()' недоступен - POSIX отклонил функции в приложении K (см. [Используете ли вы TR24731 «безопасные» функции] (http://stackoverflow.com/questions/372980/do- вы-use-the-tr-24731-safe-functions) для получения дополнительной информации), и по сути, никакая система Unix не реализует ни один из них, но доступен 'strtok_r()'. К счастью, эти два функционально идентичны. Если платформа не понятна, однозначно указывая, что 'strtok_s()' или 'strtok_r()' ... в лучшем случае вводит в заблуждение. –

3

strtok не знает о контексте, в котором он выполняется, он ведет себя несколько глобально.

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

Из man page:

Различные строки могут быть разобраны одновременно с использованием последовательностей вызовов на strtok_r(), которые определяют различные saveptr аргументы.