我正在用C编写一个超级简单的基于命令行的程序.这只是一个小测试,代码非常简单.因此,它要做的是询问用户他们的名字,数学成绩,英语成绩,计算成绩.然后它计算出他们的平均成绩,并告诉他们他们输入的名字.是的我知道这是一个非常简单的程序,但我仍然做错了.
问题是,我的代码的一部分将首先告诉用户输入他们的名字,然后一旦他们这样做并按下输入我的其余代码将立即运行然后停止工作.奇怪的是我只是不明白出了什么问题.
#include <stdio.h>
int main(int argc, const char * argv[])
{
char chr;
char firstname;
int mathsmark, englishmark, computingmark, averagemark;
printf("What is your name?\n");
scanf("%c", &firstname);
printf("\n");
printf("What is your maths mark?\n");
scanf("%d", &mathsmark);
printf("\n");
printf("What is your english mark?\n");
scanf("%d", &englishmark);
printf("\n");
printf("What is your computing mark?\n");
scanf("%d", &computingmark);
printf("\n");
printf("Your name is: %c", firstname);
printf("\n");
averagemark = (mathsmark + englishmark + computingmark) / 3;
printf("%d", averagemark);
printf("\n");
chr = '\0';
while (chr != '\n') {
chr = getchar ();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
一个主要问题是你声明firstname
是一个单个字符长,当你尝试从控制台读取名称时,你正在使用%c
转换说明符,它从输入流中读取下一个单个字符并将其存储到firstname
.名称的其余部分留在输入流中以填充剩余的scanf
呼叫.
例如,如果您键入"Jacob"作为名字,则第一个scanf
调用将分配J
给firstname
,"acob\n"
在输入流中保留.
下一个scanf
调用尝试转换"acob\n"
为整数值并将其保存为mathsmark
失败("acob\n"
不是有效的整数字符串).接下来的两个scanf
电话也会发生同样的事情.
最后一个循环
while (chr != '\n')
{
chr = getchar();
}
Run Code Online (Sandbox Code Playgroud)
最后使用"acob\n"
包含换行符的其余部分(因为在键入名称后按Enter键),导致循环和程序退出.
你是如何解决这个问题的?
首先,你需要声明firstname
为数组的char
:
char firstname[SOME_SIZE] = {0};
Run Code Online (Sandbox Code Playgroud)
哪里SOME_SIZE
足够大,可以处理所有情况.你需要改变scanf
呼叫
scanf("%s", firstname);
Run Code Online (Sandbox Code Playgroud)
这告诉scanf
从输入流中读取字符直到下一个空白字符并将结果存储到firstname
数组中.请注意,您不需要在&
此处使用运算符; 在大多数情况下,数组类型的表达式将被转换("衰减")为指针类型的表达式,表达式的值将是数组中第一个元素的地址.
请注意,这scanf
不是很安全,而且不是很强大.如果您输入的字符数超过缓冲区大小要容纳的字符数,scanf
则会很乐意将这些额外的字符存储到数组后面的内存中,这可能会破坏重要的内容.您可以通过在转换说明符中使用显式字段宽度来防止这种情况,例如
scanf(*%29s", firstname);
Run Code Online (Sandbox Code Playgroud)
但总的来说这是一种痛苦.
scanf
检测不良输入也不是很好.如果你输入"12er"作为你的一个标记,scanf
将转换并分配"12"
,留"er"
在流中以便下一次读取.
scanf
返回成功分配的数量,因此防止错误输入的一种方法是检查返回值,如下所示:
if (scanf("%d", &mathmarks) != 1)
{
printf("Bad input detected for math marks\n");
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,scanf
不会从流中删除不良字符; 你必须自己使用getchar
或类似的.