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

使用fgets()统计字符串字符出现次数出现垃圾值,gets()却正常的原因

fgets读取输入输出垃圾值,gets正常的原因及修复方法

问题重现

以下是统计字符串元素出现次数的代码,使用fgets时会输出垃圾值,改用gets则结果正常:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
int main() {
    char c[1005];
    fgets(c, 1005, stdin);
    int cnt[26] = {0};
    for (int i = 0; i < strlen(c); i++) {
        cnt[c[i] - 'a']++;
    }
    for (int i = 0; i < strlen(c); i++) {
        if(cnt[c[i]-'a'] != 0) {
            printf("%c %d\n", c[i], cnt[c[i] - 'a']);
            cnt[c[i] - 'a'] = 0;
        }
    }
    return 0;
}

使用fgets时的输出:

baaaabca
b 2
a 5
c 1

 32767

--------------------------------
Process exited after 8.61 seconds with return value 0
Press any key to continue . . . _

原因分析

  • fgets与gets的核心区别:fgets会将输入时按下的换行符\n一并读取到字符串中,而gets会自动丢弃末尾的换行符。
  • 非法数组访问导致垃圾值:当代码处理到换行符时,'\n' - 'a'的计算结果为负数(ASCII值:'\n'是10,'a'是97,10-97=-87),这会触发未定义行为——访问cnt数组的负数索引,读取到内存中的随机垃圾数据(也就是输出里的32767)。
  • gets因为自动去掉了换行符,循环不会处理到这个非法字符,所以结果正常。

修复方案

方案1:移除fgets读取的换行符

在调用fgets后,手动去掉字符串末尾的换行符:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
int main() {
    char c[1005];
    fgets(c, 1005, stdin);
    // 移除换行符
    size_t len = strlen(c);
    if (len > 0 && c[len-1] == '\n') {
        c[len-1] = '\0';
    }
    int cnt[26] = {0};
    for (int i = 0; i < strlen(c); i++) {
        cnt[c[i] - 'a']++;
    }
    for (int i = 0; i < strlen(c); i++) {
        if(cnt[c[i]-'a'] != 0) {
            printf("%c %d\n", c[i], cnt[c[i] - 'a']);
            cnt[c[i] - 'a'] = 0;
        }
    }
    return 0;
}

方案2:仅处理合法的小写字母

在统计和输出时,先判断字符是否为小写字母,避免处理换行符或其他非法字符:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
int main() {
    char c[1005];
    fgets(c, 1005, stdin);
    int cnt[26] = {0};
    for (int i = 0; i < strlen(c); i++) {
        // 仅统计小写字母
        if (islower(c[i])) {
            cnt[c[i] - 'a']++;
        }
    }
    for (int i = 0; i < strlen(c); i++) {
        if (islower(c[i]) && cnt[c[i]-'a'] != 0) {
            printf("%c %d\n", c[i], cnt[c[i] - 'a']);
            cnt[c[i] - 'a'] = 0;
        }
    }
    return 0;
}

注意:gets函数存在严重的缓冲区溢出风险,已被C标准废弃,不建议使用,优先选择fgets并配合上述修复方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:40:28