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

C语言字符串问题:未初始化访问与栈缓冲区溢出排查求助

回文字符串检测代码的栈溢出与未初始化访问问题解决

问题场景

编写回文检测代码时,明明两个字符串内容一致,却触发栈缓冲区溢出和未初始化变量访问错误。手动添加空终止符、改用fgets均未解决问题。原代码及错误信息如下:

原代码

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

#define MAX 4096

int main(void) {
    // Handle taking in input
    char str[MAX];
    int len = 0;
    while (scanf("%c", &str[len]) != EOF) {
        len++;
    }
    char str_rev[MAX];
    int j = 0;
    for (int i = len-1; i >= 0; i--) {
        str_rev[j] = str[i];
        j++;
    }
    
    if (strcmp(str, str_rev) == 0) {
        printf("String is a palindrome\n");
    } else {
        printf("String is not a palindrome\n");
    }

    return 0;
}

错误信息与变量状态

错误信息:stack buffer overflow.
执行停止时变量值:

j = 7
len = 7
str = "racecar", <4089 uninitialized values>
str_rev = "racecar", <4089 uninitialized values>
str_rev[j] = <uninitialized value>

核心原因

  1. 缺少字符串空终止符\0:C语言中,strcmp等字符串操作函数依赖末尾的\0判断字符串结束位置。原代码中:
    • str通过scanf逐个读取字符,未手动添加\0;
    • str_rev完成字符反转后,也未添加\0。
      这导致strcmp会持续读取栈上未初始化的内存区域,既触发未初始化访问警告,也可能因越界读取触发栈溢出。
  2. 输入无长度限制:while循环未检查len是否超过MAX-1,当输入字符数超过缓冲区容量时,会直接越界写入str的栈空间,触发栈溢出。
  3. 手动加终止符无效的可能原因:未在正确位置添加——比如未给str[len]和str_rev[j](即str_rev[len])赋值\0,或添加后又被后续输入覆盖。

修复方案

方案1:修正原scanf逻辑

添加长度限制和空终止符:

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

#define MAX 4096

int main(void) {
    char str[MAX];
    int len = 0;
    // 限制输入长度,预留1个位置给空终止符
    while (len < MAX - 1 && scanf("%c", &str[len]) != EOF) {
        len++;
    }
    // 给str添加字符串结束符
    str[len] = '\0';
    
    char str_rev[MAX];
    int j = 0;
    for (int i = len-1; i >= 0; i--) {
        str_rev[j] = str[i];
        j++;
    }
    // 给str_rev添加字符串结束符
    str_rev[j] = '\0';
    
    if (strcmp(str, str_rev) == 0) {
        printf("字符串是回文\n");
    } else {
        printf("字符串不是回文\n");
    }

    return 0;
}

方案2:改用fgets并处理换行符

若使用fgets需注意它会读取换行符,需手动剔除:

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

#define MAX 4096

int main(void) {
    char str[MAX];
    int len = 0;
    // 用fgets读取输入,自动添加空终止符
    if (fgets(str, MAX, stdin) != NULL) {
        len = strlen(str);
        // 去掉末尾的换行符(如果存在)
        if (len > 0 && str[len-1] == '\n') {
            str[len-1] = '\0';
            len--;
        }
    }
    
    char str_rev[MAX];
    int j = 0;
    for (int i = len-1; i >= 0; i--) {
        str_rev[j] = str[i];
        j++;
    }
    str_rev[j] = '\0';
    
    if (strcmp(str, str_rev) == 0) {
        printf("字符串是回文\n");
    } else {
        printf("字符串不是回文\n");
    }

    return 0;
}

同类问题排查要点

  • 强制检查空终止符:所有需用字符串函数处理的字符数组,必须确保末尾有\0,调试时可直接查看数组内存确认。
  • 严格限制缓冲区边界:任何写入数组的操作,必须判断索引是否小于数组长度-1(预留\0的位置),禁止越界写入。
  • 明确输入函数行为:
    • scanf("%c")会读取所有字符(包括换行、空格),不会自动加\0;
    • fgets会读取到换行符或缓冲区满,自动添加\0,但需手动处理不需要的换行符。
  • 调试时关注内存状态:通过调试工具查看数组的内存布局,确认是否存在未初始化区域、越界写入的痕迹。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:37:05