C - SCANF 第三次无法正常工作



我正在尝试编写一个简单的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:提示。

有多种方法可以解决此问题,包括:

  1. 在格式字符串中的第一个%c之前插入一个空白。 这将跳过空格(包括换行符(,并为您提供预期的行为。 这可能是最简单的解决方法。
  2. 读取行并使用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);
非整数乘法强制

使用非整数乘法、加法和除法。

最新更新