# include <math.h>
int main()
{
double a;
printf("请输入你要四舍五入的浮点数:");
while (scanf("%lf", &a) == 1)
{
printf("四舍五入后的结果为:%.0f\n", round(a));
}
return 0;
}
出现的问题:代码运行一次后,第二次循环无法打印出“请输入你要四舍五入的浮点数”。
解决办法:还是while循环的运用,运用while(1)创建一个无限循环,将一直运行的到遇到break。
# include <math.h>
int main()
{
double a;
while (1)
{
printf("请输入你要四舍五入的数:");
if (scanf("%lf", &a) != 1)
{
printf("你输入的格式错误。");
break;
}
else
{
printf("四舍五入后的结果为:%.0f\n", round(a));
}
}
return 0;
}
**程序还是存在缺陷:**当我们错误的输入2/5的时候,程序会先读取到2,然后读取到/,之后就会停止运行,
因此我们可以优化以下代码,如果发生输入错误,程序会清空剩余输入内容,从而避免解析错误和潜在的运行错误。
// 代码优化
# include <math.h>
int main()
{
double a;
char termchar;
while (1)
{
printf("请输入你要四舍五入的数:");
if (scanf("%lf%c", &a, &termchar) != 2 || termchar != '\n')
{
printf("你输入的数格式错误。\n");
while (getchar() != '\n'); // 连续读取并丢弃缓冲区中的数,直到遇到'\n',循环结束
continue;
}
printf("四舍五入后的结果是:%.0f\n", round(a));
}
return 0;
}
// 当输入我们要四舍五入的数字并按下回车后,数字返回给a,回车返回给terchar,
// 进入循环并判断格式的正误,如果输入的不是两个字符,或者第二个字符不是回车,程序都会返回格式错误
// 为避免缓冲取得字符对后续程序的影响,使用getchar()清空缓冲区的字符,知道遇到'\n'后循环结束,说明清空完毕
//continue 程序继续执行,返回”请输入你要四舍五入的数字"
记:清空缓冲区的重要性
在处理数据格式错误或者用户多输入问题时,如果不清空缓冲区,剩余数据可能会干扰到程序的下一次读取操作,可能出现无法预测的行为。通过读取后清空缓冲区,可以更好的处理错误输入和多任务输入。
如果你想处理分数的话:
# include <math.h>
# include <stdio.h>
int main()
{
int numerator, denominator; // 定义分子分母
double a;
char termchar;
while (1)
{
printf("输入你要四舍五入的数字:");
if (scanf("%d/%d%c", &numerator, &denominator, &termchar) == 3 && termchar == '\n')
{
if (denominator == 0)
{
printf("分母不能为0.\n");
continue;
}
a = (double)numerator / denominator;
printf("四舍五入后的结果为:%.0f\n", round(a));
}
else
{
// 清除缓冲区中的所有内容,包含错愕的输入
while (getchar() != '\n');
// 尝试读取浮点数
printf("尝试读取浮点数···");
if (scanf("%lf%c", &a, &termchar) == 2 && termchar == '\n')
{
printf("四舍五入后的结果是:%.0f\n", round(a));
}
else
{
printf("你输入的数格式错误。\n");
while (getchar() != '\n'); // 再次清除缓冲区
}
}
}
return 0;
}
**出现的问题:**当我们输入小数的时候,程序首先进行分数判断,发现是小数后,输出“尝试读取浮点数···”,之后会清空缓冲区,如果不清理的话,输入会留在缓冲区,因为scanf没有成功的匹配和消耗它,第二次循环时scanf会尝试读取上一次留在缓冲区的内容,这通常会导致读取失败,因为第一次可能只读取了部分数据。但是当我们清理了缓冲区后,第二次循环需要我们再次输入,这是本次改进的问题。
解决办法:使用‘fgets’和‘sscanf’这两个函数结合起来非常有用,尤其是在需要先读取一整行文本,然后再从中解析各种数据的场合。通过fgets先读整行输入到一个缓冲区,然后使用sscanf从这个缓冲区中按照指定的格式提取数据,可以有效避免不正确的个是输入导致的程序错误,同时也使得输入处理更加的灵活。
# include <stdio.h>
# include <math.h>
int main()
{
int numerator, denominator;
double a;
char input[100]; // 假设输入不超过一百个字符
while (1)
{
printf("请输入你要四舍五入的数(可以是分数、也可以是浮点数):");
if (fgets(input, sizeof(input), stdin) != NULL)
{
if (sscanf(input, "%d/%d", &numerator, &denominator) == 2)
{
if (denominator == 0)
{
printf("分母不能为零。\n");
continue;
}
if (sscanf(input, "%d/%d", &numerator, &denominator) == 2)
{
a = (double)numerator / denominator;
printf("四舍五入后的结果为:%.0f\n", a);
}
}
else if (sscanf(input, "%lf\n", &a) == 1)
{
printf("四舍五入后的结果为:%.0f\n", round(a));
}
else
{
printf("输入的格式有误。\n");
}
}
}
return 0;
}
要点: sscanf是另一个标准库函数,用于从字符串中读取格式化的数据,这与scanf相似,但是scanf是从标准输入中读取的,而是sscanf是从提供的字符传中读取.
fgets是从指定的输入流读取字符串的函数,会包括换行符(如果在输入中存在)在内的所有字符读入到提供缓冲区,然后在字符串的末尾加上空字符“\0”作为字符结束的标志。这样通常会清空输入流中的所有内容,包括换行符,因此在大多数情况下不需要考虑缓冲区的额外字符对后续程序的影响。