【问题标题】:Is there a limit to how many times the scanf function can be used? [duplicate]scanf函数的使用次数有限制吗? [复制]
【发布时间】:2013-12-17 19:22:41
【问题描述】:

为了回到 C 编程流程,我一直在输入一些简单的测试程序。我在 scanf 函数中遇到了一个奇怪的问题。我在下面的代码中有 3 个,但只有前 2 个被初始化;第三个 scanf 被忽略。这是正常的,还是我做错了什么?我盯着这段代码看了半个小时,没有发现任何错误。

#include <stdio.h>

int math(int a, int b, char selection) {

    int result;

    switch (selection) {
        case 'a':
        result = a + b;
        break;
        case 's':
        result = a - b;
        break;
        case 'm':
        result = a * b;
        break;
        case 'd':
        result = a / b;
        break;
    }

    return result;
}

int main() {
    int num1 = 0;
    int num2 = 0;
    int result = 0;
    char selection;

    printf("Enter first number: ");
    scanf("%i", &num1);

    printf("Enter second number: ");
    scanf("%i", &num2);

    printf("\n[a] Add\n[s] Subtract\n[m] Multiply\n[d] Divide\n\nWhich one: ");
    scanf("%c", &selection);

    result = math(num1, num2, selection);
    printf("%i", result);

    return 0;
}

【问题讨论】:

  • scanf 没有被忽略,它消耗了一个剩余的换行符。
  • 要获得逐个字符的输入,请使用fgetc()getc()。要获取逐行用户输入,请使用fgets()。要从二进制文件中读取,请使用 fread()(或 POSIX C 库中的 read(),如果需要/可用)。
  • @JanD - 如果您看到他的许多答案,@H2CO3 对使用 scanf() 有偏见,因为此功能隐藏的细微差别会让每个人都感到困惑。我不认为这很棘手,但使用文档和良好的调试技能,它真的不是那么糟糕的小功能
  • @Mike 好吧,除了它一贯倾向于导致缓冲区溢出,你的意思是?
  • @Mike 是的。然后您将缓冲区大小更改为 5,而您忘记更新硬编码大小。无时无刻不在发生。何必呢,既然你也可以使用fgets(buf, sizeof buf, stdin)

标签: c io scanf


【解决方案1】:

要回答您的所有问题:
scanf函数的使用次数有限制吗?

不,不,没有。

但这不是这里发生的事情。

当你做这样的事情时:

printf("Enter second number: ");
scanf("%i", &num2);

您实际上在 stdin 上输入了两个值,第一个是数字,第二个是不可见的换行符。

                     you can't see that, but it's there
                         V
> Enter second number: 3\n    

scanf() 的工作方式是,它将读取来自stdin 的输入并将其存储到您的变量中,直到它们都被填满,然后它会留下其余的。在我的示例中,3 被存储到 num2'\n' 留在 stdin 然后当这段代码运行时:

scanf("%c", &selection);

它将在stdin 上查找并找到换行符 ('\n')。这可以存储为字符类型,因此它将用它填充selection

解决此问题的一种方法是将代码更改为:

scanf(" %c", &selection);

% 之前的空格告诉scanf 忽略stdin 缓冲区开头的任何空格(包括换行符)。


调试旁注:

当您认为出现问题时,请使用调试器或打印一些值以增强您的信心和理解力。例如,我会这样更新您的代码:

printf("\n[a] Add\n[s] Subtract\n[m] Multiply\n[d] Divide\n\nWhich one: ");
int ret = scanf("%c", &selection);

printf("Scanf I think failed. Return value is: %d. Selection is: %c (%d)\n", 
        ret, selection, selection);

您可以从手册页中找到返回值的含义。在this case 中,此处的返回码将告诉您成功匹配和分配了多少项目。您会在此处看到 1,因此您知道呼叫有效。您的输出如下所示:

Scanf I think failed. Return value is: 1. Selection is:
(10)

这告诉您scanf 确实得到了一些东西,您没有看到打印的字符,但输出跳过了一行(可疑)和打印的 ASCII 值是 1010,查找它你会发现它是一个换行符。

【讨论】:

  • 我永远不会想到这一点。谢谢。
  • Minor:建议使用 %c 周围的括号代替:"Selection is:(%c) %d"
猜你喜欢
  • 1970-01-01
  • 2012-04-23
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
相关资源
最近更新 更多