には2つの問題がありますstrtok()
。
- 入力文字列を変更します。
strtok()
一度にアクティブにできるコールのセットは1つだけです。
あなたの問題は後者だと思います。コードにインデントの問題もあります。
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()
のようなものを使用する必要がある場合は、POSIXまたはMicrosoftのstrtok()
いずれかを探します(ただし、C11標準のAnnexKバージョンは異なることに注意してください。TR24731の「安全な」機能を使用していますか?を参照してください)。strtok_r()
strtok_s()
strtok_s()
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);
}
コメントについて
またはその親戚の1つを使用している間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
ます。これは利点です。