该行:
a[i] = strtok(s," ");
设置a[i]
为字符串中的指针,您正在修改该指针,最终可能会strtok
删除临时 NUL 字符(来自 )。
您可能想尝试:
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"
最终,字符串将返回到它的原始状态,并且您的指针在指向正确的地址时,不会像您期望的那样使字符串以空值结尾(最后一个除外)。
所以你最终会得到:
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
.