scanf 第三次无法正常工作

scanf doesn't work properly for third time

我正在尝试编写一个简单的 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;
}
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);

与非整数的乘法强制使用非整数乘法、加法和除法。

有 3 个格式转换说明符不会跳过前导白色 space。它们是 %c(您正在使用)、%[…] 扫描集和 %n.

当您输入时:

Enter a:<1>
Enter b:<2>

第一个<满足第一个%c1 匹配 %d> 匹配第二个 %c,所以到目前为止一切正常。

但是,第二批输入将换行符从第一行读取到第一行 %c,然后无法将 < 转换为整数并停止,留下 < 用于处理下一个输入。

给出了Enter c:提示,但是<2>因为格式正确所以处理了,所以给出了Enter d:提示

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

  1. 在格式字符串的第一个 %c 之前插入一个空格。这将跳过白色 space,包括换行符,并为您提供预期的行为。这可能是最简单的修复方法。
  2. 读取行并使用sscanf()处理它们。这通常是最好的解决方案。 (使用 fgets() 阅读该行。)

无论哪种情况,请检查 scanf() 系列函数 return 的值是否正确 (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 input\n");
        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 = %d\n", a, b, c, d);
    printf("Formula 1 result = <%lf>\n", ans);
    return 0;
}

请注意代码如何使用 fgets() 加上 sscanf(),这意味着错误消息可以告诉用户他们输入的内容不是预期的。它还使用函数 return 值,导致显示的代码更简单。并且输出包括用于检查的输入值。您的提交系统可能不需要它,但它肯定会在您开发代码时对您有所帮助。

您可以进行升级以处理 double 值作为输入;不难。