【问题标题】:Problems with Standard I/O scanf标准 I/O scanf 的问题
【发布时间】:2015-11-13 07:34:15
【问题描述】:

首先,我只想说这是来自书中的一个练习。这是一个非常简单的计算器。该练习特别说明了使用 goto 语句来完成这项工作(循环回到开头以输入另一个表达式)。我和本书的作者都知道 goto 语句通常不是一个好主意。我写了这个小程序,但我不知道为什么我不能让它工作。

#include <stdio.h>

int main(void)
{
    double num1 = 0.0;                  // first operand value a decimal number
    double num2 = 0.0;                  // second operand value a decimal number
    char oper = 0;                      // operator - must be +, -, *, /, or %
    char again = 0;

    // get the expression from the user
    Start: printf("\n\nEnter the expression: ");
    scanf("%lf %c %lf", &num1, &oper, &num2);

    switch(oper)
    {
        case '+':                       // no checks necessary for addition
            printf(" = %lf\n\n", num1+num2);
            break;
        case '-':                       // no checks necessary for subtraction
            printf(" = %lf\n\n", num1-num2);
            break;
        case '*':                       // no checks necessary for multiplication
            printf(" = %lf\n\n", num1*num2);
            break;
        case '/':
            if(num2 == 0)               // check second operand to see if it's zero
                printf("\n\n\aError:  division by zero!\n\n");
            else
                printf(" = %lf\n", num1/num2);
            break;
        case '%':
            if((long)num2 == 0)         // check second operand to see if it's zero
                printf("\n\n\aError:  division by zero!\n\n");
            else
                printf(" = %ld\n", (long)num1%(long)num2);
            break;
        default:                        // if we get here, it's an illegal operation
            printf("\n\n\aIllegal operation!\n\n");
            break;
    }
    printf("Do you want to perform another calculation?  Y/N: ");
    scanf("%c", &again);
    if((again == 'Y') || (again == 'y'))
    {
        printf("\n");
        goto Start;
    }
    return 0;
}

第一个 printf() 和 scanf() 对工作正常。但是,底部的对不起作用(在 switch 语句下方)。它将 printf() 函数中的文本打印到屏幕上,然后程序结束(我正在使用命令行运行它)。它不允许我输入“Y”以使其循环回到开头。如果我剪下这两行代码并将它们粘贴到顶部,程序会暂停并等待我的响应(它会让我输入响应)。我已经来回移动了几次线条,但我根本无法弄清楚为什么它在一个地方有效,而在另一个地方无效。

附:我不想使用 goto 语句,但这让我很恼火,因为我无法弄清楚为什么我不能从书中得到这个例子。任何帮助,将不胜感激。谢谢。

【问题讨论】:

  • 你确定不是scanf 失败了吗?您是否尝试在 scanf 调用之后直接转储变量的值?
  • 或者简单地说,检查scanf()的返回值?
  • 这看起来好像字符扫描在原始输入之后重新调整了换行符。 scanf(" %c") 在格式说明符前加一个空格可以解决您的问题。 (在我看来,更好的解决方案是使用双字符输入策略:先用fgets 读取一行,然后用sscanf 扫描。)
  • 我 100% 确定是 scanf() 失败了。 printf() 工作正常。出于某种原因,它只是跳过了 scanf() - 即不等待我输入响应。如果我将这两行移到顶部,它会暂停并允许我输入响应。它唯一不起作用的地方是我应该拥有它的地方......在底部。
  • scanf("%c", &amp;again); --> scanf(" %c", &amp;again);

标签: c


【解决方案1】:

您的第一个scanf 调用读取到double,然后是char,然后是double。因此,如果您输入1.00+2.00 然后按回车,您的输入缓冲区stdin 将包含:"1.00+2.00\n"。 scanf 系列函数的行为是,它只会从输入缓冲区中删除它读取的内容。在您第一次调用 scanf 后,stdin 缓冲区将包含 "\n"

scanf("%c", &again);

正在读取stdin 中留下的换行符\n

改成

scanf(" %c", &again);

按回车键总是会在输入缓冲区stdin 中添加一个换行符。

如果你想测试scanf()的返回值来覆盖额外的输入失败,你可以这样做:

if(scanf(" %c", &again) < 0)
{
printf("Error on scanf!");
}

more info on the nucks and crannys of the scanf function.

【讨论】:

  • 不,我不希望它打印换行符。但是,现在我已经开始工作了,我试图理解为什么标准输入中会留下一个换行符???仅仅是因为我在程序顶部按了回车提交了表达式吗?即如果我在一个程序中扫描多次,第一次扫描后总会有一个换行符需要处理?
  • 是的,换行符是你按回车造成的。
  • @JosephMills 是正确的。按 Enter 会在输入缓冲区中添加一个换行符。
  • 非常感谢你们。我会牢记这一点,以备不时之需。
【解决方案2】:

当您使用 scanf() 时,它会从标准输入读取格式化数据,并将其余数据留给标准输入,以便后续的 scanf() 调用可以读取它。在您的情况下,第一个 scanf() 读取数字,并将换行符留给标准输入。

下一个 scanf() 读取一个字符,并且由于 stdin 中已经包含换行符,它读取换行符并且不询问您的任何其他输入。

您可以通过连续添加两个 getchar() 调用、输入两个字符并按 Enter 来创建类似的异常。第二个 getchar() 不会停下来询问你的输入,因为标准输入中已经有足够的输入了。

要解决此问题,您可以将第一个 scanf() 调用更改为包含换行符(这假定用户始终提供有效输入):

scanf("%lf %c %lf\n", &num1, &oper, &num2);

【讨论】:

    【解决方案3】:

    只需插入一个getchar,如下所示: 注意:getchar() 返回输入缓冲区中的第一个字符,并将其从输入缓冲区中删除

     Start: printf("\n\nEnter the expression: ");
        scanf("%lf %c %lf", &num1, &oper, &num2);
        getchar();//inset this line
    // rest of the code will same
    

    需要include&lt;string.h&gt;

    【讨论】:

      猜你喜欢
      • 2012-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 1970-01-01
      • 2012-03-19
      • 2012-09-22
      • 2013-02-05
      相关资源
      最近更新 更多