1613551 发表于 2023-6-30 20:08:32

关于scanf函数的问题

没有看懂这串代码,在第三次调用scanf函数的时候,我输入了2.5q加上好几个回车,按道理应该是不满足第二个do while的条件了,但是却一直没有结束循环,直到输入了2.5再按回车才结束

#include <stdio.h>
#include <stdlib.h>
int main()
{
    float num = 0;
    double sum = 0;
    int status;

    do
    {
      printf("请输入合法的数字:");
      do
      {
            sum = sum + num;
            status = scanf("%f", &num);
      } while (getchar() != '\n' && status == 1);
    } while (status == 1);

    printf("结果是:%.2lf\n", sum);
    system("pause");
    return 0;
}

isdkz 发表于 2023-6-30 20:10:18

你好,这段代码的逻辑是:用户需要不断输入数字,这些数字将会被累加到sum中。程序会一直等待用户的输入,直到用户输入了非数字。

程序使用了scanf函数来获取用户的输入,并用一个浮点数来存储这个输入。 scanf会返回成功读取的数据项数量,如果成功读取了一个浮点数, scanf就会返回 1。

在内层的do-while循环中, getchar() != '\n'和status == 1必须同时满足才能继续循环。 getchar()函数会读取下一个可用的字符,如果这个字符不是换行符,并且scanf成功读取了一个浮点数,那么就继续循环。否则,退出循环。

然后在外层的do-while循环中,如果status == 1 ,即scanf成功读取了一个浮点数,那么就继续循环,否则退出循环。

但是你的问题是在第三次调用scanf时输入了 "2.5q",这在scanf函数看来是一个不合法的输入,所以它只会读取 "2.5",并将 "q" 留在输入流中。此时, scanf依然会返回 1,表示成功读取了一个浮点数。然后getchar()函数会读取 "q",因为 "q" 不等于换行符,所以内层的do-while循环会继续。这就造成了你的问题,即使你输入的不是一个合法的浮点数,程序也会继续运行,直到读取到一个合法的浮点数为止。

如果你想让程序在用户输入非数字时就立即退出,你需要修改你的程序,使其能够处理非数字的输入。有很多方法可以实现这个功能,比如使用strtol或strtod函数,它们能够报告非数字的位置。你还可以使用fgets函数来获取一整行的输入,然后使用sscanf或strtol / strtod来解析这个输入。

1613551 发表于 2023-6-30 20:16:36

isdkz 发表于 2023-6-30 20:10
你好,这段代码的逻辑是:用户需要不断输入数字,这些数字将会被累加到sum中。程序会一直等待用户的输 ...

但是为什么我输入了很多个回车,它也还是没有退出循环,然后再次输出printf呢

isdkz 发表于 2023-6-30 20:19:08

1613551 发表于 2023-6-30 20:16
但是为什么我输入了很多个回车,它也还是没有退出循环,然后再次输出printf呢

在你的代码中,当你输入了 "2.5q" 并按下回车后,这些字符被存储在输入流中。scanf会读取并解析 "2.5",然后将 "q" 以及之后的换行符留在输入流中。在这个状态下, scanf会返回 1,表示它成功地读取了一个浮点数。这就导致了内层do-while循环的继续执行。

然后, getchar会读取输入流中的下一个字符,也就是 "q"。因为 "q" 不等于换行符,所以内层do-while循环继续执行。

接下来, scanf尝试从输入流中读取下一个浮点数,但是此时输入流中的下一个字符是换行符,所以scanf无法读取到浮点数,于是返回 0。

在这种情况下, getchar会读取到输入流中的换行符,所以getchar() != '\n'的结果为false ,于是内层的do-while循环终止。

然后,外层的do-while循环检查status的值。由于status是 0,所以外层的do-while循环也终止。

在这之后,由于你在程序中没有添加任何的退出条件,所以程序会继续运行,直到你关闭它。

当你输入多个回车的时候,因为没有输入任何的浮点数, scanf会直接返回 0,但此时getchar仍然会读取到换行符,所以getchar() != '\n'的结果为false ,于是内层的do-while循环终止。然后,由于status是 0,所以外层的do-while循环也终止。然后程序会再次开始执行,这就解释了为什么你看到了多次 "请输入合法的数字:" 的提示。

如果你希望在用户没有输入任何东西,只是按了回车的情况下,程序就退出,那么你需要在do-while循环中添加一个适当的退出条件。比如,你可以在调用scanf之前,先用fgets读取一行输入,然后再使用sscanf来解析这个输入。如果fgets返回NULL ,说明用户没有输入任何东西,只是按了回车,此时你可以退出循环。

1613551 发表于 2023-6-30 20:24:06

isdkz 发表于 2023-6-30 20:19
在你的代码中,当你输入了 "2.5q" 并按下回车后,这些字符被存储在输入流中。scanf会读取并解析 "2.5 ...

感觉还是没有完全懂

1613551 发表于 2023-6-30 20:24:52

isdkz 发表于 2023-6-30 20:19
在你的代码中,当你输入了 "2.5q" 并按下回车后,这些字符被存储在输入流中。scanf会读取并解析 "2.5 ...

我的疑惑是,
为什么输入2.5q2.5【回车】可以退出循环
但是输入了2.5q【回车】【回车】【回车】却无法退出循环

1613551 发表于 2023-6-30 20:27:07

{:10_266:}

isdkz 发表于 2023-6-30 20:31:19

1613551 发表于 2023-6-30 20:24
我的疑惑是,
为什么输入2.5q2.5【回车】可以退出循环
但是输入了2.5q【回车】【回车】【回车】却无法 ...

好的,我明白你的困惑了。这个问题的答案其实在于scanf函数和getchar函数如何处理输入流。

在你的代码中,当你输入 "2.5q" 并按下回车后,"2.5q\n" 被放入了输入流中。scanf会读取并解析 "2.5",然后将 "q\n" 留在输入流中。在这个状态下, scanf会返回 1,表示它成功地读取了一个浮点数。这就导致了内层do-while循环的继续执行。

然后, getchar会读取输入流中的下一个字符,也就是 "q"。因为 "q" 不等于换行符,所以内层do-while循环继续执行。

接下来, scanf尝试从输入流中读取下一个浮点数,但是此时输入流中的下一个字符是换行符,所以scanf无法读取到浮点数,于是返回 0。

在这种情况下, getchar会读取到输入流中的换行符,所以getchar() != '\n'的结果为false ,于是内层的do-while循环终止。然后,外层的do-while循环检查status的值。由于status是 0,所以外层的do-while循环也终止。

然而,当你输入 "2.5q\n\n\n" 的时候,情况就有所不同。首先, scanf会读取并解析 "2.5",然后将 "q\n\n\n" 留在输入流中。此时, scanf返回 1, getchar读取到 "q",于是内层do-while循环继续执行。

接下来, scanf尝试从输入流中读取下一个浮点数,但是此时输入流中的下一个字符是换行符,所以scanf无法读取到浮点数,于是返回 0。此时, getchar会读取到输入流中的换行符,所以getchar() != '\n'的结果为false ,于是内层的do-while循环终止。

然后,外层的do-while循环检查status的值。由于status是 0,所以外层的do-while循环也终止,然后再次开始新一轮的外层循环。在这个新一轮的外层循环中, scanf尝试从输入流中读取一个浮点数,但是输入流中的下一个字符还是换行符,所以scanf无法读取到浮点数,返回 0。此时, getchar会读取到输入流中的换行符,于是内层的do-while循环又一次在第一次迭代中就终止了。

所以,当你输入 "2.5q\n\n\n" 的时候,程序其实是在不断地开始新的外层循环,但是每一次的内层循环都在第一次迭代中就终止了。

当你输入 "2.5q2.5\n" 的时候,"2.5q2.5\n" 被放入了输入流中。 scanf会读取并解析前面的 "2.5",然后将 "q2.5\n" 留在输入流中。然后getchar读取到 "q",然后scanf尝试读取下一个浮点数,这次它会成功地读取到 "2.5",于是返回 1。然后getchar读取到 "\n",于是内层do-while循环终止。外层do-while循环检查status的值,由于status是 1,所以外层do-while循环继续执行。然后程序会再次询问你输入下一个数字。

1613551 发表于 2023-6-30 20:39:51

本帖最后由 1613551 于 2023-6-30 20:41 编辑

isdkz 发表于 2023-6-30 20:31
好的,我明白你的困惑了。这个问题的答案其实在于scanf函数和getchar函数如何处理输入流。

在 ...

我还是没有理解,如果说是不断开始新的外层循环,为什么不会一直输出printf,而是卡在那里不动了呢,也就是图一第三段那里

所以,当你输入 "2.5q\n\n\n" 的时候,程序其实是在不断地开始新的外层循环,但是每一次的内层循环都在第一次迭代中就终止了。

1613551 发表于 2023-6-30 21:19:52

{:10_254:}

1613551 发表于 2023-6-30 21:26:48

{:10_266:}是谁设置的最佳答案

sfqxx 发表于 2023-6-30 22:03:42

1613551 发表于 2023-6-30 21:26
是谁设置的最佳答案

{:10_256:}

sfqxx 发表于 2023-6-30 22:04:29

你再发一个帖子吧,说说你的疑惑

1613551 发表于 2023-6-30 22:21:28

sfqxx 发表于 2023-6-30 22:04
你再发一个帖子吧,说说你的疑惑

{:10_250:}

sfqxx 发表于 2023-6-30 22:23:23

1613551 发表于 2023-6-30 22:21


主要是我差1最佳答案就第2了呀{:10_266:},帮帮吧。

sfqxx 发表于 2023-7-12 23:28:47

”自找的“,给了最佳就别想了

1613551 发表于 2023-7-14 19:47:20

sfqxx 发表于 2023-7-12 23:28
”自找的“,给了最佳就别想了

噗,这个啊,真不好意思,我当时没看到
页: [1]
查看完整版本: 关于scanf函数的问题