我正在尝试编写一个简单的C程序。输入格式如下所示:
Enter a: <a>
我想输入 a、b、c 和 d,但 scanf 不适用于 c 和 d,程序在该点崩溃。
#include <stdio.h>
#include <math.h>
int main(){
int a, b, c, d;
char ch;
printf("Enter a:");
scanf("%c%d%c", &ch, &a, &ch);
printf("Enter b:");
scanf("%c%d%c", &ch, &b, &ch);
printf("Enter c:");
scanf("%c%d%c", &ch, &c, &ch);
printf("Enter d:");
scanf("%c%d%c", &ch, &d, &ch);
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
ans=fabs(ans);
printf("Formula 1 result = <%lf>", ans);
return 0;
}
有 3 个格式转换说明符不会跳过前导空格。 它们是%c
(您正在使用的(、%[…]
扫描集和%n
。
当您键入:
Enter a:<1>
Enter b:<2>
第一个<
满足第一个%c
;1
匹配%d
,>
匹配第二个%c
,所以到目前为止一切都很好。
然而,第二批输入将换行符从第一行读取到第一%c
,然后无法将<
转换为整数并停止,将<
留给下一个输入进行处理。
给出了Enter c:
提示,但处理了<2>
,因为它的格式正确,因此给出了Enter d:
提示。
有多种方法可以解决此问题,包括:
- 在格式字符串中的第一个
%c
之前插入一个空白。 这将跳过空格(包括换行符(,并为您提供预期的行为。 这可能是最简单的解决方法。 - 读取行并使用
sscanf()
来处理它们。 这通常是最好的解决方案。 (使用fgets()
阅读该行。
在任一情况下,请检查 scanf()
系列函数是否返回正确的值 (3(。 使用两个变量int c1, c2;
来读取字符并验证用户是否键入了所需的字符。
最低限度的修正是:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a, b, c, d;
char c1, c2;
printf("Enter a: ");
if (scanf(" %c%d%c", &c1, &a, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!n"), exit(1);
printf("Enter b: ");
if (scanf(" %c%d%c", &c1, &b, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!n"), exit(1);
printf("Enter c: ");
if (scanf(" %c%d%c", &c1, &c, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!n"), exit(1);
printf("Enter d: ");
if (scanf(" %c%d%c", &c1, &d, &c2) != 3 || c1 != '<' || c2 != '>')
fprintf(stderr, "Bogus input!n"), exit(1);
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
ans=fabs(ans);
printf("Formula 1 result = <%lf>n", ans);
return 0;
}
我在if
语句之后对逗号运算符很懒惰。 不过,最好使用函数来管理输入:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static void get_number(int *var, const char *name)
{
char c1, c2;
printf("Enter %s: ", name);
if (scanf(" %c%d%c", &c1, var, &c2) != 3 || c1 != '<' || c2 != '>')
{
fprintf(stderr, "Bogus input!n");
exit(1);
}
}
int main(void)
{
int a, b, c, d;
get_number(&a, "a");
get_number(&b, "b");
get_number(&c, "c");
get_number(&d, "d");
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
ans=fabs(ans);
printf("Formula 1 result = <%lf>n", ans);
return 0;
}
最好还是使用:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static int get_number(const char *name)
{
char buffer[4096];
printf("Enter %s: ", name);
if (fgets(buffer, sizeof(buffer), stdin) == 0)
{
fprintf(stderr, "EOF or error on inputn");
exit(1);
}
char c1, c2;
int val;
if (sscanf(buffer, " %c%d%c", &c1, &val, &c2) != 3 || c1 != '<' || c2 != '>')
{
/* buffer contains a newline unless you typed more than 4095 characters before the newline */
fprintf(stderr, "Bogus input (does not match <number>): %s", buffer);
exit(1);
}
return val;
}
int main(void)
{
int a = get_number("a");
int b = get_number("b");
int c = get_number("c");
int d = get_number("d");
double ans = fabs((a*b/c + c*d/a) / (b*a/c + d*b/a));
printf("Inputs: a = %d, b = %d, c = %d, d = %dn", a, b, c, d);
printf("Formula 1 result = <%lf>n", ans);
return 0;
}
请注意代码如何使用fgets()
加sscanf()
这意味着错误消息可以告诉用户他们输入的内容不是预期的。 它还使用该函数返回值,从而显示更简单的代码。 输出包括用于检查的输入值。 您的提交系统可能不需要这样做,但它肯定会在您开发代码时为您提供帮助。
您可以进行升级以将double
值作为输入进行处理;这并不难。
double ans;
ans=(a*b/c + c*d/a)/(b*a/c + d*b/a);
C 语言在确定结果类型时不会考虑您对结果执行的操作。因此,将此操作的结果分配给double
这一事实对结果的计算方式没有任何影响,它只是将整数结果转换为双精度值。当您将整数除以整数时,您将获得整数除法。
你可以做这样的事情:
ans=(a*1.0*b/c + c*1.0*d/a)/(b*1.0*a/c + d*1.0*b/a);
非整数乘法强制使用非整数乘法、加法和除法。