【问题标题】:How do I limit the input of scanf to integers and floats (numbers in general)如何将 scanf 的输入限制为整数和浮点数(一般为数字)
【发布时间】:2018-12-11 14:55:02
【问题描述】:

我目前正在大学学习 C 编程,我得到了编写一个程序的任务,该程序将任意函数 ax^2+bx+c 的 0 / x 轴的截点输出。

为了确保输入正确(int、float 等),我运行以下while 循环。在此之前,a 被定义为双精度。

printf("Input for a=");

while (scanf("%lf", &a) == 0)
{
    fflush(stdin);
    scanf("%lf", &a);
    printf("Incorrect Input! New Input needed.\n"); 
    printf("a=");
}

我知道fflush(stdin) 运算符仅在发生第二个输入函数时清除缓冲区,因此循环内的fflush 不会清除缓冲区,因此循环的条件始终为真,因此我创建了一个无限循环。

我的教授也禁止使用goto,这就是我在这里的原因,因为我想不出一个合理的解决方案来解决这个问题。 我也尝试过但失败了:

do
{
    printf("\nInput for a= ");
    scanf("%lf", &a);
}

while (isdigit(a));
{
    printf("Thank you.\n");
}

通过这种安排,我收到了失败通知:Expression c >= -1 && <= 255。我想这与错误的变量定义(双精度、数字)等有关。

但是我最初的问题是是否有一个优雅的解决方案来解决这个问题,或者至少有任何解决方案。

【问题讨论】:

  • fflush(stdin) 是未定义的行为,不要这样做。
  • 如果您现在对整个程序感兴趣:pastebin.com/0ELkCiS7
  • 在做任何其他事情之前,请正确indent您的程序。这一点很重要,对我们来说不是那么重要,而是四个
  • 您是否在问如何使用相同的scanf 语句获取输入并区分intfloat?或者,您只是想将输入限制为一个或另一个?在任何一种情况下,最好将块包含在一个连续循环中,例如for (;;) { int rtn = scanf (...); ... } 验证返回 (rtn),如果输入正确,只需 break;。为什么? scanf 可以在失败时返回 0EOF,并且使用 == 0 控制循环将无法检测到 EOF
  • 扫描后它就消失了。用fgets 读取一行更灵活。如果一个sscanf 不起作用,您可以用另一个重试。而且很容易转储该行并阅读另一行。

标签: c scanf fflush


【解决方案1】:

Lukas,我仍然不是 100% 清楚,你的:

“我在问如何区分所有数字和 scanf 的所有其他可能输入。”

scanf 可以根据使用的转换说明符 提供到单个给定类型的转换,因此您不能使用相同的scanf 语句同时读取intfloat 和单个转换说明符。 (现在您可以读取一行,例如 fgets,然后使用备用 sscanf 语句并检查剩余的字符来执行此操作)

也就是说,我想我理解您的问题,并且可以回答fflush 和阅读价值问题。

首先,在使用scanf 时,您必须检查返回并处理三种情况。 (1) EOF,用户使用 Ctrl+d (或 Windows 上的 Ctrl+z)取消输入; (2) 发生匹配输入失败,导致返回少于使用的转换说明符的数量;最后是 (3) 良好的输入案例(您可以在其中进行任何额外的检查,例如肯定的、小于 100 等)

虽然fflush(stdin) 在大多数系统上是未定义的行为,但有许多实现允许它。 (主要是 windows,但 Linux 允许它用于 seekable 流,例如在 stdin 上重定向的文件)底线,它是不可移植的,没有警告,所以最好提供一个简单的与 @987654333 等效的@,例如

void empty_stdin (void)
{
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

至于scanf,正如我在评论中提到的,将scanf 调用包含在一个无限循环中要容易得多,只有在输入满足所有约束时才会中断该循环。一个需要整数输入的简单示例是:

int getint (int *value, const char *prompt)
{
    /* loop continually until good input or canceled */
    for (;;) {
        int rtn;
        fputs (prompt, stdout);     /* display prompt */
        rtn = scanf ("%d", value);

        if (rtn == EOF) {   /* user generated manual EOF */
            fputs ("<user canceled input>\n", stderr);
            return 0;
        }
        empty_stdin();  /* all other cases - empty input buffer */
        if (rtn == 1)   /* good input, break */
            break;
        /* otherwise matching failure */
        fputs ("  error: invalid integer input.\n", stderr);
    }
    return *value;  /* value also availale through pointer */
}

把它放在一个简单的例子中,你会:

#include <stdio.h>

void empty_stdin (void)
{
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

int getint (int *value, const char *prompt)
{
    /* loop continually until good input or canceled */
    for (;;) {
        int rtn;
        fputs (prompt, stdout);     /* display prompt */
        rtn = scanf ("%d", value);

        if (rtn == EOF) {   /* user generated manual EOF */
            fputs ("<user canceled input>\n", stderr);
            return 0;
        }
        empty_stdin();  /* all other cases - empty input buffer */
        if (rtn == 1)   /* good input, break */
            break;
        /* otherwise matching failure */
        fputs ("  error: invalid integer input.\n", stderr);
    }
    return *value;  /* value also availale through pointer */
}

int main (void) {

    int v,
        i = getint (&v, "enter integer value: ");

    if (i)
        printf ("\ninteger: %d\n", v);

    return 0;
}

使用/输出示例

您现在可以尽最大努力打破您编写的任何输入例程。如果你发现了问题,就去修复它并尝试再次破坏它。

上面的代码允许对任何一种给定类型的值进行相当稳健的输入,例如

$ ./bin/scanfint
enter integer value: no
  error: invalid integer input.
enter integer value: apples, banannas, and pears
  error: invalid integer input.
enter integer value: 21

integer: 21

查看一下,如果您的问题略有不同,或者您对答案还有其他问题,请告诉我。

【讨论】:

  • 感谢这个非常详细的遮阳篷!我认为这将解决我的问题。如果我仍然无法解决它,我可能会回来.. 无论如何谢谢!
  • 2 个想法:fflush(stdout); 之间的 fputs (prompt, stdout); rtn = scanf ("%d", value); 使得在输入之前看到一定的提示。当empty_stdin();ferror() 而返回时,我希望getint() 会像if (rtn == EOF) 一样返回,但这是一个微妙的点。
  • 我并不是在 fputs (prompt, stdout); rtn = scanf ("%d", value); 之间建议 empty_stdin()。我建议fflush(stdout);
  • 好吧,这更有意义。我匆忙地读了它,并认为您使用了一种速记来冲洗stdin,是的,冲洗stdout 是有道理的。但是,由于scanf 是一个输入函数,它会在此时强制刷新stdout。那里不会重复吗?
猜你喜欢
  • 2021-06-07
  • 2018-01-24
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
  • 2016-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多