分析的代码开头是:
fgets(input,sizeof(input),stdin);
if("\n"==input[strlen(input)-1]) // to remove '\n' from string
input[strlen(input)-1]=='\0';
您应该检查来自fgets() 的返回值,以便您知道input 中是否有任何数据需要分析。
if 应该是 if (input[strlen(input)-1] == '\n'),测试字符 '\n' 而不是字符串 "\n"*。您应该已经收到有关类型不匹配的编译器警告。如果您没有收到此类警告,请使用更好的编译器。如果您收到警告,请注意您的编译器;它比你更了解 C(并且不会仅仅为了好玩而生成警告)。
if 之后的赋值需要一个单一的= 而不是一个双重的==——您可能应该收到关于什么都不做的语句的警告。
* 我知道有些人推荐订单if ('\n' == input[strlen(input)-1]),但对我来说并不那么好。该机制旨在防止 == 与 = 条件中的错误。它是不完美的——例如,当 LHS 和 RHS 都是变量时(if (lhs = rhs))它不能保护你——如果你有一个伪装成条件的赋值,一个体面的编译器会警告你(就像它会警告你一样关于伪装成作业的条件)。
代码应该这样开始,因此:
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
我忽略了重复调用strlen() 的“低效率”;还有更大的问题需要担心。注意修改后的代码检查输入操作的结果;如果fgets() 检测到 EOF 或错误并且您没有测试fgets() 的结果,您就会遇到麻烦。
代码的原始版本然后继续:
if(input == "point"){
scanf("%d %d",&x1,&y1);
point(x1,y1);
}
if(input == "rectangle"){
scanf("%d %d",&x1,&y1,&x2,&y2);
rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
}
正如jambono 在他的answer 中正确指出的那样,这不起作用;你不能像那样比较字符串。
不幸的是,重写是:
if(strcmp(input,point)==0){
scanf("%d %d",&x1,&y1);
point(x1,y1);
}
if(strcmp(input,rectangle)==0){
scanf("%d %d",&x1,&y1,&x2,&y2);
rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
}
这也应该从编译器生成警告,因为字符串已更改为函数指针 - 编译器应该抱怨将函数指针转换为 const char * 或类似的位置。
正确的比较可能是:
if (strcmp(input, "point") == 0)
if (strcmp(input, "rectangle") == 0)
只要单词单独出现在一行上,这些数据就可以工作:
point
1 2
rectangle
2 3 4 5
问题前的答案已格式化以提高可读性
当然,第二个scanf() 需要修复格式字符串,您应该始终测试scanf() 是否按预期工作:
if (scanf("%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...deal with error...
请注意,scanf() 调用将把换行符留在后面,准备好被另一个调用 fgets() 作为行上唯一的字符(剩下的)读取。我认为第二次调用 fgets() 读取包含数据的行,然后使用 sscanf() 解析该行可能会更好。
组装所有更改(使用scanf()):
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
if (strcmp(input, "point") == 0)
{
if (scanf("%d %d",&x1,&y1) != 2)
...report format error and return/exit...
point(x1, y1);
}
else if (strcmp(input, "rectangle") == 0)
{
if (scanf("%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...report format error and return/exit...
rectangle(x1, y1, x2, y2);
}
else
...unexpected input (format error)...
}
使用fgets() 和sscanf():
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
if (strcmp(input, "point") == 0)
{
if (fgets(input, sizeof(input), stdin) == 0)
...report unexpected EOF and return/exit...
if (sscanf(input, "%d %d",&x1,&y1) != 2)
...report format error and return/exit...
point(x1, y1);
}
else if (strcmp(input, "rectangle") == 0)
{
if (fgets(input, sizeof(input), stdin) == 0)
...report unexpected EOF and return/exit...
if (sscanf(input, "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...report format error and return/exit...
rectangle(x1, y1, x2, y2);
}
}
请注意,在使用fgets() 的示例中,您拥有可以报告给用户的整行输入,这对于他们来说可能比在scanf() 阅读了该行之后找到剩下的内容更容易,并且拒绝转换其余的。例如,如果输入是:
rectangle
10 10 2O 22
O 上的转换将失败(应该是 0),但您可以从输入中收集到的唯一信息以向用户报告是 O 22,这可能不是就像能够显示整行一样有用。
问题后的答案已格式化以提高可读性
输入是单行:
point 1 1
rectangle 1 0 0 1
在这种情况下,您不能使用scanf() 来获取数字(因为fgets() 已经阅读了整行),因此您将需要使用sscanf() 并且不需要再次调用@ 987654368@。但是,您必须修改比较代码以及对sscanf() 的调用。我会创建一个小函数来检查给定字符串是否是另一个字符串的前缀:
int str_prefix(const char *haystack, const char *needle)
{
return strncmp(haystack, needle, strlen(needle)) == 0;
}
如果needle 可以在haystack 的开头找到,则返回true。如果您有 C99 或更高版本的编译器,则可以使用 static inline 对其进行限定(并且可以明智地将返回类型更改为 bool 或 _Bool)。
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
if (str_prefix(input, "point "))
{
if (sscanf(input, "point %d %d",&x1,&y1) != 2)
...report format error and return/exit...
point(x1, y1);
}
else if (str_prefix(input, "rectangle "))
{
if (sscanf(input, "rectangle %d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...report format error and return/exit...
rectangle(x1, y1, x2, y2);
}
}
注意“needle”字符串的尾随空格。这可以防止您将“指出的评论”误解为“点”线的开始。
您可以在关键字之后开始 sscanf() 搜索,而不是使用关键字开始格式字符串:
if (sscanf(&input[sizeof("rectangle")], "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)