V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
WilliamColton
V2EX  ›  C

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

  •  
  •   WilliamColton · 36 天前 · 2603 次点击
    这是一个创建于 36 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用的 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 条回复    2024-03-24 11:13:33 +08:00
    NessajCN
        1
    NessajCN  
       36 天前   ❤️ 1
    没有复现,建议检查自身环境
    PTLin
        2
    PTLin  
       36 天前   ❤️ 1
    这种问题自己打个断点调试一下比来这里问更快的。
    ben666
        3
    ben666  
       36 天前   ❤️ 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  
       36 天前
    奇怪问题通常是蠢原因。 比如开了两个窗口(真实经历)
    WilliamColton
        5
    WilliamColton  
    OP
       36 天前
    @PTLin #2
    @ben666 #3
    @GeruzoniAnsasu #4
    没有开两个窗口
    同时调试了,第二次运行 scanf 收到的是第一次的结果。。。
    WilliamColton
        6
    WilliamColton  
    OP
       36 天前

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

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

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

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

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

    @GenericT #10 没有啊
    aa514758835
        12
    aa514758835  
       36 天前
    把中间文件删干净重新编译把,我有时候也会遇到明明是 false 但是走了 true 分支的情况
    GenericT
        13
    GenericT  
       36 天前
    建议把整个 workspace 打包上传,不然没法判断
    yolee599
        14
    yolee599  
       36 天前
    @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  
       36 天前   ❤️ 1
    在纯净的终端里用 mingw 的 gcc/clang 编译然后运行,然后复现你的问题,整理成流程最后再来问吧。要不现在这样也没人可以复现,问也没意义。
    sbldehanhan
        16
    sbldehanhan  
       36 天前
    程序两次运行之间没有任何联系。所以,第一次影响第二次是不可能发生的。遇到问题先从自己身上找原因,相信计算机比人靠谱。
    tool2d
        17
    tool2d  
       36 天前
    用 mingw gcc 编译了一下,没办法复现,结果倒是对的。
    4
    1 2 3 4
    2
    3
    4
    1
    CEBBCAT
        18
    CEBBCAT  
       36 天前   ❤️ 1
    尝试使用输入重定向来解决,我怀疑你复制粘贴的字符掺杂了不可见字符之类的。

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

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

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

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

    建议好好检查下空格状况
    WilliamColton
        27
    WilliamColton  
    OP
       35 天前
    @cnbatch #25 这空格不影响结果

    cnbatch
        28
    cnbatch  
       35 天前   ❤️ 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
       35 天前
    @cnbatch #28 好的,感谢指点:)
    nevermoreluo
        30
    nevermoreluo  
       35 天前
    单纯有点好奇你的 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  
       34 天前   ❤️ 1
    @nevermoreluo Do not write`fflush(stdin)`, it's a bad practice.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2883 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 12:46 · PVG 20:46 · LAX 05:46 · JFK 08:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.