You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中for循环未修改变量mistake却自动变为0的问题排查

问题原因分析

1. 缓冲区溢出直接篡改mistake值

你的代码中char password[6]仅分配6字节空间,但gets()函数完全不检查输入长度。当输入的密码超过5个字符(字符串需要1字节存储\0结束符),超出部分会越界写入栈上password后方的内存区域——而mistake变量恰好位于这个位置,越界的字符会直接覆盖mistake的内存值,导致它被意外改成0。

比如输入123456(6个字符),password的6个位置存满字符后,字符串结束符\0会被写到第7个字节,也就是mistake的内存起始位置,直接将mistake的低字节置0,最终变量值变为0。

2. 输入缓冲区残留换行符引发逻辑异常

gets(password)读取密码后,输入的换行符会留在标准输入缓冲区。后续scanf("%d\n", &mistake)中的\n会让scanf持续等待非空白字符,直到输入数字后再输入额外空白才返回;进入循环后,gets(guess)会先读取缓冲区残留的换行符,导致guess被设为空字符串,后续字符比较逻辑完全混乱。

3. 其他潜在问题

  • count变量未在每次循环后重置,第一次验证失败后的累计值会带到下一次循环,导致后续即使输入正确密码,也可能因count不等于6无法触发正确提示。
  • 直接硬比较6个字符,若输入密码长度不足6,数组后续字节为随机垃圾值,会导致比较结果错误。
  • gets()是C标准已废弃的不安全函数,无任何缓冲区溢出防护,是代码隐患的核心根源。

解决方案

以下是修复后的完整代码,同时解决所有问题:

#include <stdio.h>
#include <string.h>

int main()
{
    // 分配足够空间,留足字符串结束符位置,限制输入长度避免溢出
    char password[10];
    // 用fgets替代gets,安全读取输入
    if (fgets(password, sizeof(password), stdin) == NULL) {
        return 1;
    }
    // 去掉fgets读取到的换行符,保证字符串格式正确
    password[strcspn(password, "\n")] = '\0';
    // 校验密码长度(匹配原代码逻辑,要求5个字符)
    if (strlen(password) != 5) {
        printf("密码必须是5个字符\n");
        return 1;
    }

    int mistake = 0;
    // 清理缓冲区残留的换行符
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
    printf("请输入尝试次数:");
    // 校验尝试次数输入有效性
    if (scanf("%d", &mistake) != 1 || mistake <= 0) {
        printf("输入无效的尝试次数\n");
        return 1;
    }
    // 清理scanf后的换行符,避免影响后续读取
    while ((c = getchar()) != '\n' && c != EOF);

    char guess[10];
    for(int i = 0; i < mistake; i++)
    {
        printf("请输入密码:");
        if (fgets(guess, sizeof(guess), stdin) == NULL) {
            return 1;
        }
        guess[strcspn(guess, "\n")] = '\0';
        // 先校验输入长度
        if (strlen(guess) != 5) {
            printf("密码长度错误\n");
            if (i == mistake - 1) {
                printf("you were electrocuted\n");
                return 0;
            }
            continue;
        }

        // 用strcmp直接比较字符串,替代手动循环,避免垃圾值干扰
        if (strcmp(password, guess) == 0) {
            printf("correct\n");
            return 0;
        } else {
            if (i == mistake - 1) {
                printf("you were electrocuted\n");
                return 0;
            } else {
                printf("wrong password\n");
            }
        }
    }

    return 0;
}

关键修复点

  • 用fgets()替代gets(),通过第二个参数限制读取长度,彻底杜绝缓冲区溢出。
  • 用strcspn()去除fgets()读取到的换行符,保证字符串格式正确。
  • 每次输入后清理标准输入缓冲区的残留字符,避免后续读取操作出错。
  • 用strcmp()直接比较字符串,替代手动循环比较,逻辑更简洁且避免垃圾值干扰。
  • 增加输入有效性校验(密码长度、尝试次数合法性),提升代码健壮性。

内容的提问来源于stack exchange,提问作者Jack C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:01:00