分析的代码开始于:
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])
,但对我来说并不好。该机制旨在防止条件中的==
vs=
错误。它是不完善的——例如,当 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在他的回答中正确指出的那样,这是行不通的;你不能像那样比较字符串。
不幸的是,重写是:
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
转换将在( 应该是 a )上失败0
,但是您可以从输入中收集到的唯一信息以向用户报告是O 22
,这可能不如能够显示整行有用。
为了便于阅读,问题被格式化后回答
输入是单行:
point 1 1
rectangle 1 0 0 1
在这种情况下,您不能使用scanf()
来获取数字(因为fgets()
已经阅读了整行),因此您将需要使用sscanf()
并且不需要第二次调用fgets()
. 但是,您必须修改比较代码以及对sscanf()
. 我会创建一个小函数来检查给定字符串是否是另一个字符串的前缀:
int str_prefix(const char *haystack, const char *needle)
{
return strncmp(haystack, needle, strlen(needle)) == 0;
}
如果needle
可以在 的开头找到,则返回 true haystack
。如果您有 C99 或更高版本的编译器,则可以使用static inline
(并且可以明智地将返回类型更改为bool
or _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);
}
}
请注意“针”字符串上的尾随空格。这可以防止您将“尖锐的评论”误解为“点”线的开始。
您可以在关键字之后开始搜索,而不是使用关键字开始格式字符串sscanf()
:
if (sscanf(&input[sizeof("rectangle")], "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)