一个简单(奇怪)的 C 语言问题 - V2EX
WilliamColton
V2EX    C

一个简单(奇怪)的 C 语言问题

  •  
  •   WilliamColton Mar 22, 2024 4766 views
    This topic created in 787 days ago, the information mentioned may be changed or developed.

    使用的 IDE 是 CLion ,编译器是其自带的 MinGW 11.0 w64

    下面的代码使用 chatgpt 加了注释,主要的问题是:

    在直接给定输入

    8 1 9 2 6 0 8 1 7 

    时,结果为 0.

    而再次给定输入

    8 1 9 2 6 90 8 1 7 

    时,结果还是 0.

    而手动一个一个输入则正常显示 1.

    虽然描述的很离奇,但是确实是这样,即:第一次的结果会影响第二次的结果,使之变成第一次的结果

    我问了我们教 C 语言的老师,连他也不知道怎么回事,说可能是 CLion 的问题,但是这个答案并不能令我信服,

    故来寻求各位 V 友帮助

    求各位 V 友解答 QAQ

    代码如下:

    #include <stdio.h> int main() { int n; scanf("%d", &n); // 从标准输入中读取一个整数,存储到变量 n 中 int min; scanf("%d", &min); // 假设输入的第一个数为最小值,存储到变量 min 中 int num; for (int i = 1; i < n; i++) { // 循环读取剩余的 n-1 个整数 scanf("%d", &num); // 从标准输入中读取一个整数,存储到变量 num 中 printf("%d\n", num); // 将读取的整数打印到标准输出,以换行符结束 if (num < min) { // 检查当前读取的整数是否比最小值小 min = num; // 更新最小值为当前读取的整数 } } printf("%d", min); // 打印最小值到标准输出 return 0; // 返回 0 表示程序正常结束 } 
    31 replies    2024-03-24 11:13:33 +08:00
    NessajCN
        1
    NessajCN  
       Mar 22, 2024   1
    没有复现,建议检查自身环境
    PTLin
        2
    PTLin  
       Mar 22, 2024   1
    这种问题自己打个断点调试一下比来这里问更快的。
    ben666
        3
    ben666  
       Mar 22, 2024   1
    遇到问题
    1. 单步调试
    2. printf 打印调试

    另外,注意一下 C 代码风格与规范,参考:
    1. linux kernel 规范: https://www.kernel.org/doc/html/v4.10/process/coding-style.html
    2. nginx 规范: https://nginx.org/en/docs/dev/development_guide.html#code_style

    也可以参考 https://github.com/baidu/dperf/ 的代码风格
    GeruzoniAnsasu
        4
    GeruzoniAnsasu  
       Mar 22, 2024
    奇怪问题通常是蠢原因。 比如开了两个窗口(真实经历)
    WilliamColton
        5
    WilliamColton  
    OP
       Mar 22, 2024
    @PTLin #2
    @ben666 #3
    @GeruzoniAnsasu #4
    没有开两个窗口
    同时调试了,第二次运行 scanf 收到的是第一次的结果。。。
    WilliamColton
        6
    WilliamColton  
    OP
       Mar 22, 2024

    可以看见明明是 0 ,却读入了 5a (即 90 )
    mightybruce
        7
    mightybruce  
       Mar 22, 2024   1
    代码结果我没有复现, 给你一点提示
    scanf() 并不是直接让用户从键盘输入数据,而是先检查缓冲区,处理缓冲区中的数据

    scanf() 的这些特性都是有章可循的,其根源就是行缓冲区。

    当遇到 scanf() 函数时,程序会先检查输入缓冲区中是否有数据:

    如果没有,就等待用户输入。用户从键盘输入的每个字符都会暂时保存到缓冲区,直到按下回车键,产生换行符\n ,输入结束,scanf() 再从缓冲区中读取数据,赋值给变量。
    如果有数据,那就看是否符合控制字符串的规则

    如果能够匹配整个控制字符串,那最好了,直接从缓冲区中读取就可以了,就不用等待用户输入了。
    如果缓冲区中剩余的所有数据只能匹配前半部分控制字符串,那就等待用户输入剩下的数据。
    smdbh
        8
    smdbh  
       Mar 22, 2024
    scanf 是回车有效吧,如果是一行输入,就是 ```scanf("%d%d%d %d%d%d%d%d", &min[0],&min[1], .... &min[7], );``` 前后都是 8 个
    bugcoder
        9
    bugcoder  
       Mar 22, 2024
    你在 return 一句前面加上 fflush(stdin); 把输入缓存清空一下。 一般 scanf 出问题都是缓存的问题。
    GenericT
        10
    GenericT  
       Mar 22, 2024
    Clion 有个运行配置有个“重定向输入自”,你是不是在里面放东西了
    WilliamColton
        11
    WilliamColton  
    OP
       Mar 22, 2024
    @bugcoder #9 无效

    @GenericT #10 没有啊
    aa514758835
        12
    aa514758835  
       Mar 22, 2024
    把中间文件删干净重新编译把,我有时候也会遇到明明是 false 但是走了 true 分支的情况
    GenericT
        13
    GenericT  
       Mar 22, 2024
    建议把整个 workspace 打包上传,不然没法判断
    yolee599
        14
    yolee599  
       Mar 22, 2024
    @smdbh #8 正解,按照 OP 给出的代码,应该这样输入:
    8\n
    1\n
    9\n
    2\n
    6\n
    0\n
    8\n
    1\n
    7\n

    而不是这样:
    8\n
    1 9 2 6 0 8 1 7\n
    PTLin
        15
    PTLin  
       Mar 22, 2024   1
    在纯净的终端里用 mingw 的 gcc/clang 编译然后运行,然后复现你的问题,整理成流程最后再来问吧。要不现在这样也没人可以复现,问也没意义。
    sbldehanhan     16
    sbldehanhan  
       Mar 22, 2024
    程序两次运行之间没有任何联系。所以,第一次影响第二次是不可能发生的。遇到问题先从自己身上找原因,相信计算机比人靠谱。
    tool2d
        17
    tool2d  
       Mar 22, 2024
    用 mingw gcc 编译了一下,没办法复现,结果倒是对的。
    4
    1 2 3 4
    2
    3
    4
    1
    CEBBCAT
        18
    CEBBCAT  
       Mar 22, 2024   1
    尝试使用输入重定向来解决,我怀疑你复制粘贴的字符掺杂了不可见字符之类的。

    例如,echo '8\n\n1 2 3\n' > t; cat t | od -xa; cat t | ./a.exe

    已经会用调试器了啊,很好,这些奇奇怪怪的问题可以追查,相信最后要不发现哭笑不得的错误,要不然就是对计算机有更多了解。或者也可以切换到其他平台比如 Linux macOS 。

    另外,论坛里面有很多半吊子的,网上也是,有的时候别太信。小马过河,尽量规避因为别人的鼠目寸光给自己带来的误导
    MoYi123
        19
    MoYi123  
       Mar 22, 2024
    如果要在 clion 的 terminal 里输入, 推荐把 Emulate terminal in the output console 打开
    araraloren
        20
    araraloren  
       Mar 22, 2024
    @yolee599 `scanf` can handle the input correctly, you don't need enter line by line.
    lff0305
        21
    lff0305  
       Mar 22, 2024
    在 Linux 下用 GCC 测试了下没有发现问题

    这个问题是否和 Clion 的 Console 有关系?
    WilliamColton
        22
    WilliamColton  
    OP
       Mar 22, 2024
    @sbldehanhan #16 仔细一想确实应该如此
    @CEBBCAT #18 嗯嗯,谢谢您真诚的建议! :)
    @lff0305 #21 就是 CLion 的 Console 有问题!我在同学电脑上也试了一下,依旧是这个问题,但是直接运行他编译出来的程序就不会这样。感谢提醒!!!
    @araraloren #20 你这个才是正解
    我会向 JetBrains 写邮件反馈的!谢谢各位!
    nevermoreluo
        23
    nevermoreluo  
       Mar 22, 2024
    同 Clion2023.3.4 ,mingw11 没复现
    建议自己断点 debug 找找吧,这里总共也没多少数
    WilliamColton
        24
    WilliamColton  
    OP
       Mar 22, 2024
    @nevermoreluo #23 但是我在同学电脑的 CLion 上都可成功复现,应该是我和你方法不一样?
    然后我已经设断点找过了,代码一运行到那里就 num 就变成 0 ,进去 scanf 也没看出啥有用的信息来,再进一层就是汇编了,这个是真看不懂(能力有限,大一新生,望谅解)
    我等会再找一个同学安装 CLion 试试
    同时下面两张图是我的方法
    cnbatch
        25
    cnbatch  
       Mar 22, 2024   1
    第九行那个 scanf ,双引号内有个空格,但你原贴给出的代码,这一行的双引号内没空格
    cnbatch
        26
    cnbatch  
       Mar 22, 2024
    还有第 12 行也是一样

    建议好好检查下空格状况
    WilliamColton
        27
    WilliamColton  
    OP
       Mar 22, 2024
    @cnbatch #25 这空格不影响结果

    cnbatch
        28
    cnbatch  
       Mar 23, 2024   1
    我自己用 Windows 11 + VS2022 试了下,没法复现错误,最终输出是 1
    在 FreeBSD 14 + Clang 16 试了下,也是没问题,最终输出还是 1
    Linux 就不试了,前面已经有人测试过

    个人建议,不要死磕 CLion 控制台,而是改用常规环境。
    鬼知道 CLion and/or 它自带的 MinGW 是不是有 bug 。

    尤其像这次,正常命令行环境运行测试程序没任何问题,CLion 控制台一用就出错,那只能是 CLion 的锅。

    至于常规环境,例如:
    Windows: MSVC 最新版,直接用 Visual Studio 即可
    Linux: 编译器 GCC 或 Clang 均可,IDE 随意
    BSD: 编译器用系统自带的,IDE 随意
    macOS: Apple Clang

    尤其是 Windows ,用 Visual Studio 反倒最稳妥
    WilliamColton
        29
    WilliamColton  
    OP
       Mar 23, 2024
    @cnbatch #28 好的,感谢指点:)
    nevermoreluo
        30
    nevermoreluo  
       Mar 23, 2024
    单纯有点好奇你的 for(;;) 里面是什么

    下面属于根据结果瞎猜了

    就是兄弟咱不能写出直接往标准输出里面写 0 的东西吧。。。。

    ```
    printf("min: %d", min); // 打印最小值到标准输出
    fflush(stdin);
    for (;;){

    write(1, "0", 1); // 这样的话对句柄标准输出直接写的这个 0 会先输出,printf 如果不 fflush(stdout)的话要等程序退出才会打印 就会在后面
    scanf(" %d", &n);
    if (n == -1){ break; }
    }
    ```

    ```
    # Clion Console
    8

    1 9 2 6 90 8 1 7
    0-1 // 0 是 write 函数输出的,-1 是输入赋值给 n 的
    min: 1
    ```
    araraloren
        31
    araraloren  
       Mar 24, 2024   1
    @nevermoreluo Do not write`fflush(stdin)`, it's a bad practice.
    About     Help     Advertise     Blog     API     FAQ     Solana     1097 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 70ms UTC 18:29 PVG 02:29 LAX 11:29 JFK 14:29
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86