この線:
a[i] = strtok(s," ");
a[i]
変更中の文字列内のポインターに設定され、最終的に一時的な NUL 文字 (からstrtok
) が削除される可能性があります。
あなたは試してみたいかもしれません:
a[i] = strdup (strtok (s," "));
代わりは。
さらに説明しましょう。コマンドがあるとします(メモリに存在するため):
ls -al xyzzy\0
あなたがstrtok
それをすると、ほぼ確実に次のように変更されます。
ls\0-al xyzzy\0
^
そして、s
( で示される^
) から返されstrtok
、 に配置されa[0]
ます。次回は、文字列を次のように変更します。
ls -al\0xyzzy\0
^
で示されるアドレスを取得し^
、それを に挿入しa[1]
ます。残念ながら、a[0]
現在は文字列を指しています"ls -al"
最終的に、文字列は元の状態に戻り、ポインターは正しいアドレスを指していますが、期待どおりに文字列が null で終了することはありません (最後のアドレスを除く)。
したがって、次のようになります。
a[0] = "ls -al xyzzy"
a[1] = "-al xyzzy"
a[2] = "xyzzy"
を使用してstrdup
、各文字列のコピーを作成します (文字列が期待どおりの時点で、単一の単語)。これは、文字列のトークン化コードの後の操作によって変更されません。
ただし、使い終わったら、割り当てたすべての文字列を解放することを忘れないでください。
このコードをベースラインとして使用できます。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void) {
char str[256], *word[20];
int i, num, len;
printf ("Enter command: ");
fgets (str, sizeof (str), stdin);
num = 0;
word[num] = strtok (str, " ");
while (word[num] != NULL) {
word[num] = strdup (word[num]);
len = strlen (word[num]);
if (strlen (word[num]) > 0)
if (word[num][len-1] == '\n')
word[num][len-1] = '\0';
word[++num] = strtok (NULL, " ");
}
for (i = 0; i < num; i++) {
printf ("%d: [%s]\n", i, (word[i] == NULL) ? "<<null>>" : word[i]);
free (word[i]);
}
return 0;
}
次のトランスクリプトは、実際の動作を示しています。
Enter command: ls -al xyzzy | grep -v plugh
0: [ls]
1: [-al]
2: [xyzzy]
3: [|]
4: [grep]
5: [-v]
6: [plugh]
さらに、C 文字列を比較する正しい方法は次のとおりではありません。
if (a[0] = "cd")
アドレスを比較するため、バッキング コンテンツが同じであってもアドレスが異なる可能性があります。代わりに次のようなものを使用する必要があります。
if (strcmp (a[0], "cd") == 0)
最後に、argv[]
渡す配列にexecvp
は、最終的な終了 NULL ポインターが必要です。これはコントラクトの一部であるため、 を呼び出す前に が含まれていることを確認する必要がありますexecvp
。