我正在编写一个程序,该程序解析来自stdin的输入并根据输入调用函数。 我的程序应该处理的输入如下:
end //stops the program
report //prints a specific output
addent "ent_id"
delent "ent_id"
addrel "ent_id1" "ent_id2" "rel_id"
delrel "ent_id1" "ent_id2" "rel_id"
输入调用的函数与我的问题无关,但请注意传递给函数的所有参数都在引号之间。
这是代码
int main() {
const char Comando[6][7] = { "addrel", "addent", "delrel", "delent", "report", "end" };
const char spazio[2] = " ";
const char newline[3] = "\n";
const char quote[2] = "\"";
char sample[100];
char *temp;
char *comandoIN;
char *argomento1;
char *dest;
char *rel;
RelHead = NULL;
init_array();
char *str = fgets(sample, 100, stdin);
for (;;) {
if (strncmp(sample, Comando[5], 3) == 0) {
return 0;
} else if (strncmp(sample, Comando[4], 6) == 0) {
report();
} else {
temp = strtok(sample, newline);
comandoIN = strtok(temp, spazio);
argomento1 = strtok(NULL, quote);
if (strncmp(Comando[1], comandoIN, 7) == 0) {
addent(argomento1);
} else if (strncmp(Comando[3], comandoIN, 7) == 0) {
delent(argomento1);
} else {
temp = strtok(NULL, quote);
dest = strtok(NULL, quote);
temp = strtok(NULL, quote);
rel = strtok(NULL, quote);
if (strncmp(Comando[0], comandoIN, 7) == 0) {
addrel(argomento1, dest, rel);
} else if (strncmp(Comando[2], comandoIN, 7) == 0) {
delrel(argomento1, dest, rel);
}
}
}
char *str = fgets(sample, 69, stdin);
}
return 0;
}
不正确的行为是由以下输入引起的:
addrel "The_Ruler_of_the_Universe" "The_Lajestic_Vantrashell_of_Lob" "knows"
,这导致strtok
的最后两个调用分别返回NULL
(而不是" "
(空格)和"knows"
(不带引号)。
此外,如果这是给程序的第一个输入,则它的行为正确,如果是最后一个,则下一个循环会将"knows"
放入"comandoIN"
变量中。这是我到目前为止发现的唯一导致此问题的输入,我认为这与第一次调用strtok
删除换行符有关。
这是uni的一项工作,因此我们有几个输入来测试程序,我的程序通过了其中的前4个(每个测试大约有200个输入),所以我不太了解是什么导致了该错误。有什么想法吗?
答案 0 :(得分:3)
这里的问题是输入:
addrel "The_Ruler_of_the_Universe" "The_Lajestic_Vantrashell_of_Lob" "knows"
长度为77个字节(76个字符加上终止NULL)。
在循环结束时,您有:
char *str = fgets(sample, 69, stdin);
您声明缓冲区的长度为69。
如果它是第一个输入,为什么它的行为正确?
在进行for循环之前:
char *str = fgets(sample, 100, stdin);
for(;;)
...
这里使用的大小为100,因此如果您在启动程序后直接使用上面的输入,则可以使用它。
答案 1 :(得分:1)
使用strtok
来使用不同的分隔符集来解析命令行会造成混乱并且容易出错。用一个简单的循环解析命令行并显式处理空格和引号,然后分派第一个单词会更简单。
这是一种较为系统的方法:
#include <stdio.h>
char *getarg(char **pp) {
char *p = *pp;
char *arg = NULL;
while (*p == ' ')
p++;
if (*p == '\0' || *p == '\n')
return arg;
if (*p == '"') {
arg = ++p;
while (*p != '\0' && *p != '"')
p++;
if (*p == '"')
*p++ = '\0';
} else {
arg = p++;
while (*p != '\0' && *p != ' ' && *p != '\n')
p++;
if (*p != '\0')
*p++ = '\0';
}
*pp = p;
return arg;
}
int main() {
char sample[100];
char *cmd, *arg1, *arg2, *arg3;
RelHead = NULL;
init_array();
while (fgets(sample, sizeof sample, stdin)) {
char *p = sample;
cmd = getarg(&p);
arg1 = getarg(&p);
arg2 = getarg(&p);
arg3 = getarg(&p);
if (cmd == NULL) { // empty line
continue;
} else
if (!strcmp(cmd, "end")) {
break;
} else
if (!strcmp(cmd, "report")) {
report();
} else
if (!strcmp(cmd, "addent")) {
addent(arg1);
} else
if (!strcmp(cmd, "delent")) {
delent(arg1);
} else
if (!strcmp(cmd, "addrel")) {
addrel(arg1, arg2, arg3);
} else
if (!strcmp(cmd, "delrel")) {
delrel(arg1, arg2, arg3);
} else {
printf("invalid command\n");
}
}
return 0;
}