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

C语言字符串处理函数异常:程序冻结、变量值异常求解

你的代码问题分析与修正方案

首先,咱们来拆解你遇到的几个核心问题:

1. 程序冻结/j数值异常的根本原因

你在遍历原字符串的同时直接修改它,这会彻底破坏原字符串的结束标记'\0'。

举个例子:当你执行s[index++] = s[i]时,会把原字符串的字符逐个覆盖,包括原本存储'\0'的位置。内层循环的终止条件是s[j] != '\0',一旦'\0'被覆盖,j就会无限制递增,开始访问超出input数组范围的内存(这在C里属于未定义行为)——这就是为什么j会变成700、2000这种奇怪数值,甚至导致程序冻结或崩溃。

2. 提取重复字符的逻辑错误

现在的代码只要s[i] == s[j]就把字符加入结果,这意味着:

  • 对于每个i,j从0遍历到末尾,每一次匹配都会添加一次字符。比如输入"cheese",i=2(第一个'e')时,j=2、3、5都会匹配,会添加3个'e';当i=3(第二个'e')时,又会再添加3个'e',最后结果会充满冗余字符,完全不符合你想要的提取重复字符的目标。

3. 结束符赋值的小错误

你写的s[++index] = '\0'是错的:index在最后一次s[index++]后,已经指向结果的下一个空位置,直接赋值s[index] = '\0'就足够了。++index会让你跳过一个位置,可能导致数组越界,还会让结果字符串多一个无效的空字节。

4. 额外小问题:fgets的换行符

fgets会把你输入时的回车符'\n'也存入input数组,处理前最好先把它去掉,不然结果里会包含这个多余的换行符。


修正后的代码(满足你输入cheese输出eee的需求)

下面的代码先统计每个字符的出现次数,再遍历原字符串收集所有出现次数大于1的字符,同时避免了修改原字符串时破坏遍历的问题:

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

char *repeticoes(char *s) {
    // 先去掉fgets带来的换行符
    size_t len = strlen(s);
    if (len > 0 && s[len-1] == '\n') {
        s[len-1] = '\0';
    }

    int count[256] = {0}; // 统计每个ASCII字符的出现次数
    char *result = s; // 复用原数组空间,先统计再填充
    int index = 0;

    // 第一次遍历:统计所有字符的出现次数
    for (int i = 0; s[i] != '\0'; i++) {
        count[(unsigned char)s[i]]++;
    }

    // 第二次遍历:收集出现次数>1的字符
    for (int i = 0; s[i] != '\0'; i++) {
        if (count[(unsigned char)s[i]] > 1) {
            result[index++] = s[i];
        }
    }

    result[index] = '\0'; // 正确添加字符串结束符
    return result;
}

int main() {
    char input[21];
    printf("str 1\n");
    fgets(input, sizeof(input), stdin);
    repeticoes(input);
    printf("duplicated letters %s\n", input);
    return 0;
}

如果你的需求是提取去重后的重复字符集合(比如输入cheese输出e),可以在代码里加一个added数组标记已经添加过的字符:

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

char *repeticoes(char *s) {
    size_t len = strlen(s);
    if (len > 0 && s[len-1] == '\n') {
        s[len-1] = '\0';
    }

    int count[256] = {0};
    int added[256] = {0}; // 标记字符是否已添加到结果中
    char *result = s;
    int index = 0;

    for (int i = 0; s[i] != '\0'; i++) {
        count[(unsigned char)s[i]]++;
    }

    for (int i = 0; s[i] != '\0'; i++) {
        unsigned char c = (unsigned char)s[i];
        if (count[c] > 1 && !added[c]) {
            result[index++] = c;
            added[c] = 1;
        }
    }

    result[index] = '\0';
    return result;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:59:36