【问题标题】:How to let scanf() keep reading integer inputs unless a character is input?除非输入字符,否则如何让 scanf() 继续读取整数输入?
【发布时间】:2023-03-10 23:22:01
【问题描述】:

我正在尝试编写一个程序来读取用户的输入并确定整数是否为斐波那契。

程序应该打印出num is fibnum is not fib,其中num是一个正整数;

如果输入是非正数,程序不应该产生任何输出(但它应该在stderr上产生错误信息)并且应该不断提示;

如果输入包含任何字符,则程序不应产生任何输出(但应在 stderr 上产生错误消息)然后退出。

这是预期的结果:

1 2 3 4 5
1 is fib
2 is fib
3 is fib
4 is not fib
5 is fib

(不断提示输入)

1 -2 3 -4 5
1 is fib
Error: input value -2 is not positive
3 is fib
Error: input value -4 is not positive
5 is fib

(不断提示输入)

1-23-45
1 is fib
Error: input value -23 is not positive
Error: input value -45 is not positive

(不断提示输入)

12a
12 is not fib
Error: input is not a number

我能够检查第一个输入数字,但完成后,程序会自行退出。如何让scanf() 知道何时继续阅读以及何时退出?

这是我的代码

int main() {
    int num, x, y, z;

    while (scanf("%d", &num) > 0) {
        if (num <= 0) {
            fprintf(stderr, "Error: input value %d is not positive\n", num);
            return -1;
        } else {
            x = 0;
            y = 1;
            z = x + y;
            while (z < num) {
                x = y;
                y = z;
                z = x + y;
            }
            if (z == num) {
                printf("%d is fib\n", num);
            } else {
                printf("%d is not fib\n", num);
            }
            return 0;
        }
    }
    return 0;
}

【问题讨论】:

  • 您的代码(尚未)报告“不是数字”。
  • 程序是否应该在文件末尾静默退出?
  • @chqrlie 是的,一旦涉及字符就退出,然后向 stderr 发送消息
  • @Crysishy:这不准确:如果有字母等违规字符,您需要一条错误消息,但如果在我们到达文件末尾时输入中没有剩余字符,为什么你应该有错误消息吗?

标签: c


【解决方案1】:

scanf 返回小于1 时,您当前退出main 函数。如果stdin 中存在不以数字开头的字符,例如ascanf("%d", &amp;num) 将返回0,您将退出程序,但没有消息。在第一个结果之后,您还以return 0; 退出,这是不正确的。

当一个数字不能被解析并且只在文件末尾静默退出,当scanf返回EOF时,你必须改变逻辑:

#include <stdio.h>

int main(void) {
    int status, num, x, y, z, exit_code = 0;

    while ((status = scanf("%d", &num)) >= 0) {
        if (status == 0) {
            fprintf(stderr, "Error: input is not a number\n");
            return 1;
        }
        if (num <= 0) {
            fprintf(stderr, "Error: input value %d is not positive\n", num);
            exit_code = 1;
            continue;
        }
        x = 0;
        y = 1;
        z = x + y;
        while (z < num) {
            x = y;
            y = z;
            z = x + y;
        }
        if (z == num) {
            printf("%d is fib\n", num);
        } else {
            printf("%d is not fib\n", num);
        }
    }
    return exit_code;
}

【讨论】:

  • 当输入包含任何字符,如 1.1 或 1a2 时,程序应该退出,那么我该如何实现呢?此外,当输入为负数或 0 时,程序不应该产生任何输出(但它应该在 stderr 上产生错误消息),那么我原始代码中的“fscanf”是否正确?
  • 为什么“fprintf”下的“return 1”,我认为返回值应该传达异常执行,所以它应该是“return -1”。 “继续”是什么意思?这是否意味着回到更大的while循环?抱歉问了这么多问题,因为我对 C 很陌生:
  • scanf什么时候返回EOF?
  • @Crysishy: C11 7.21.6.2: 如果在第一次转换(如果有)完成之前发生输入错误,fscanf 函数将返回宏 EOF 的值。否则,该函数返回分配的输入项的数量,如果出现早期匹配失败,该数量可能少于提供的数量,甚至为零。 实际上,scanf 在最后返回 EOF文件。
  • @Crysishy:return 1; 是错误代码。来自main 的任何非零返回值都可能表示某些错误情况,它是系统特定的。如果您愿意,可以return -1;,但在 unix 下,退出状态值通常被限制在一个很小的范围内,例如 0..127
【解决方案2】:

这是因为您从程序中的所有条件中返回。在 else 子句中不带 return 0 尝试以下操作:

int main(){
    int num,x,y,z;

    while (scanf("%d", &num) > 0){
        if (num <= 0){
            fprintf(stderr, "Error: input value %d is not positive\n", num);
        }
        else {
            x = 0;
            y = 1;
            z = x + y;
            while (z < num){
                x = y;
                y = z;
                z = x + y;
            }
            if (z == num){
                printf("%d is fib\n", num);
            }
            else {
                printf("%d is not fib\n", num);
            }
        }
    }
    if(feof(stdin))
        return 0;
    fprintf(stderr, "Error: input value is not a number\n");
    return 1;
}

【讨论】:

  • 很好地抓住了额外的return 0;,但如果输入流中有一个字母,您仍然会退出循环。
  • @chqrlie:我认为这是他想要的行为。如果你看他的测试用例:'1 2 a b c',它只打印出一个错误并退出程序。
  • 你读到负数后返回;你不应该继续——要么简单地删除return -1,要么改用continue? (在我看来,使用 continue 并没有那么好。)
  • @Pooya:如果是字母,你确实正确退出了,但你也应该输出input is not a number
  • 更好。我们当中的超级批评者可能会注意到“不是数字”和 EOF 之间存在区别。为了捕捉到这一点,您可以将scanf() 返回的值保存到一个变量中,并测试该变量是 0(不是数字)还是 EOF(……EOF,当然……)以报告差异,如果您需要通知根本没有EOF。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
相关资源
最近更新 更多