Есть две проблемы с strtok()
.
- Он изменяет свою входную строку.
- Одновременно может быть активен только один набор
strtok()
вызовов.
Я думаю, что ваша проблема в последнем. У вас также есть проблема с отступами в коде:
if (scanf(" %[^\n]", line) > 0)
token = strtok( line, ";" );
do
{
line2 = token;
temporaryToken = strtok(line2, " ");
do
{
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok(NULL, " ");
} while (temporaryToken != NULL);
token = strtok( NULL, ";" );
} while(token != NULL);
Вероятно, вы имели в виду следующее:
if (scanf(" %[^\n]", line) > 0)
{
token = strtok(line, ";");
do
{
line2 = token;
temporaryToken = strtok(line2, " ");
do
{
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok(NULL, " ");
} while (temporaryToken != NULL);
token = strtok(NULL, ";");
} while (token != NULL);
}
Предполагая, что это то, что вы намеревались, у вас все еще есть проблема, заключающаяся в том, что один strtok()
работает на line
, а второй работает на line2
. Проблема в том, что цикл на line2
полностью разрушает интерпретацию line
. Вы не можете использовать вложенные циклы с strtok()
.
Если вы должны использовать что-то вроде strtok()
, найдите либо POSIX < a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok_r.html" rel="nofollow noreferrer">strtok_r()
или strtok_s()
(но обратите внимание, что версия strtok_s()
в приложении K стандарта C11 отличается — см. Используете ли вы «безопасные» функции TR 24731?).
if (scanf(" %[^\n]", line) > 0)
{
char *end1;
token = strtok_r(line, ";", &end1);
do
{
char *end2;
line2 = token;
temporaryToken = strtok_r(line2, " ", &end2);
do
{
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok_r(NULL, " ", &end2);
} while (temporaryToken != NULL);
token = strtok_r(NULL, ";", &end1);
} while (token != NULL);
}
О комментариях
Пока вы используете strtok()
или один из его родственников, входная строка будет изменена, и если у вас есть несколько разделителей, вы не сможете определить, какой разделитель присутствовал. Вы можете работать с копией строки и выполнять сравнения (обычно на основе смещений от начала строки).
В пределах использования strtok_r()
приведенное выше решение «работает». Вот тестовая программа для демонстрации:
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[1024];
if (scanf(" %[^\n]", line) > 0)
{
char *end1;
char *token;
printf("Input: <<%s>>\n", line);
token = strtok_r(line, ";", &end1);
do
{
char *end2;
char *line2 = token;
char *temporaryToken;
printf("Token1: <<%s>>\n", token);
temporaryToken = strtok_r(line2, " ", &end2);
do
{
printf("Token2: <<%s>>\n", temporaryToken);
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok_r(NULL, " ", &end2);
} while (temporaryToken != NULL);
token = strtok_r(NULL, ";", &end1);
} while (token != NULL);
}
return 0;
}
Пример ввода и вывода:
$ ./strtok-demo
ls -la; mkdir lololol; ls -la
Input: <<ls -la; mkdir lololol; ls -la>>
Token1: <<ls -la>>
Token2: <<ls>>
Token2: <<-la>>
Token1: << mkdir lololol>>
Token2: <<mkdir>>
Token2: <<lololol>>
Token1: << ls -la>>
Token2: <<ls>>
Token2: <<-la>>
$
Альтернатива с использованием strcspn()
и strspn()
Если вы не хотите разрушать исходную строку, вы должны использовать другие функции, кроме семейства strtok()
. Подходят функции strcspn()
и strspn()
; они являются частью стандарта C (C89 и более поздние версии), хотя и гораздо менее известны, чем некоторые другие функции. Но они идеально подходят для этой задачи.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *substrdup(const char *src, size_t len);
int main(void)
{
char line[1024];
if (scanf(" %[^\n]", line) > 0)
{
char *start1 = line;
size_t len1;
printf("Input: <<%s>>\n", line);
while ((len1 = strcspn(start1, ";")) != 0)
{
char *copy = substrdup(start1, len1);
char *start2 = copy;
size_t len2;
printf("Token1: %zd <<%.*s>>\n", len1, (int)len1, start1);
printf("Copy: <<%s>>\n", copy);
start2 += strspn(start2, " "); // Skip leading white space
while ((len2 = strcspn(start2, " ")) != 0)
{
printf("Token2: %zd <<%.*s>>\n", len2, (int)len2, start2);
start2 += len2;
start2 += strspn(start2, " ");
}
free(copy);
start1 += len1;
start1 += strspn(start1, ";");
}
printf("Check: <<%s>>\n", line);
}
return 0;
}
#include <assert.h>
static char *substrdup(const char *src, size_t len)
{
char *copy = malloc(len+1);
assert(copy != 0); // Apalling error handling strategy
memmove(copy, src, len);
copy[len] = '\0';
return(copy);
}
Пример ввода и вывода:
$ strcspn-demo
ls -la; mkdir lololol; ls -la
Input: <<ls -la; mkdir lololol; ls -la>>
Token1: 140734970342872 <<>>
Copy: <<ls -la>>
Token2: 2 <<ls>>
Token2: 3 <<-la>>
Copy: << mkdir lololol>>
Token2: 5 <<mkdir>>
Token2: 7 <<lololol>>
Copy: << ls -la>>
Token2: 2 <<ls>>
Token2: 3 <<-la>>
Check: <<ls -la; mkdir lololol; ls -la>>
$
Этот код восходит к более удобному циклу while
, вместо того, чтобы использовать циклы do-while
, что является преимуществом.
person
Jonathan Leffler
schedule
11.08.2012