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

C语言循环错误引发栈缓冲区溢出问题求助

回文检测程序栈溢出问题排查

这是一项作业任务:编写C程序,提示用户输入短语并判断是否为回文,禁止使用strlen()、strcmp()等内置字符串处理函数。程序可正常编译,但输入任意字符后触发stack-buffer-overflow错误,怀疑even_count函数循环存在问题。

报错信息

This frame has 1 object(s):
    [32, 62) 'pali_array' (line 30) <== Memory access at offset 95 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/Execise in C/3.10.c:92 in even_count

程序源码

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

int Check_Pali(char pali_array[30],int count);
void lower_conversion(char pali_array[30],int count);
int odd_count(char pali_array[30],int middle);
int even_count(char pali_array[30],int middle);

int main(void){
    char c;
    int flag;
    int count=0;
    char pali_array[30];
    int i;
    while((c=getchar()!='\n')){
        for(i=0;i<30;i++){
        //fill the array with getchar.
        pali_array[i]=c;
        count++;
        if(ispunct(pali_array[i])||isspace(pali_array[i])){
            i--;
            count--;
        }
        //putchar(pali_array[i]);
    }
    }

    flag=Check_Pali(pali_array,count);
    if(flag==1){
        printf("These are not Palindromes!\n");
        }
            else{
                printf("These are Palindromes!\n");
            }
}

int Check_Pali(char pali_array[30],int count){
    int middle;
    int flag;
    //Set all the letters to lower case.
    if(count%2==0){
        middle=(count)/2;
        flag=even_count(pali_array,middle);
        return flag;
    }else{
        middle=count/2;
        flag=odd_count(pali_array,middle);
        return flag;
    }
}
//Turn all the char into lower case.
void lower_conversion(char pali_array[30],int count){
    int i;
    for(i=0;i<count;i++){
        pali_array[i] = tolower(pali_array[i]);
    }
}
//when middle is an odd number.
int odd_count(char pali_array[30],int middle){
    int i;
    int flag=0;
    for(i=1;i<=middle;i++){
        if(pali_array[middle-i]!=pali_array[middle+i]){
            flag=1;
        }
    }
    return flag;
}
//when middle is an even number.
int even_count(char pali_array[30],int middle){
    int i;
    int j=1;
    int flag=0;
    for(i=0;i<middle;i++){
        if((pali_array[middle+i])!=pali_array[middle-j+1]){
            flag=1;
        }
        j++;
    }
    return flag;
}

编译参数

cc -Wall -Wextra -Wfloat-equal -pedantic -Wvla -std=c99 -g3 -fsanitize=address -fsanitize=undefined

问题根源分析

  1. main函数输入逻辑完全错误

    • 运算符优先级错误:while((c=getchar()!='\n')) 实际是把getchar()!='\n'的布尔值(0或1)赋值给c,而非输入字符。正确写法应为while( (c = getchar()) != '\n' )。
    • 嵌套for循环无意义:会将同一个字符重复写入数组30次,直接导致count异常增大,后续数组访问越界。
    • 跳过标点空格的逻辑错误:当前逻辑会在写入数组后再回退索引,容易引发索引混乱。
  2. even_count函数索引计算错误
    当输入长度为偶数时,回文比较的索引逻辑完全错误。例如长度为4(middle=2),正确的比较应为索引0 vs 3、1 vs 2,但当前代码会错误计算为2 vs 2、3 vs 1,不仅逻辑错误,还可能在长度较大时触发数组越界。

  3. 其他隐性问题

    • lower_conversion函数从未被调用,导致大小写字符无法统一,回文判断结果错误。
    • odd_count函数存在越界风险:当count异常增大时,middle+i会超出数组索引范围。

修复后的代码

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

int Check_Pali(char pali_array[], int count);
void lower_conversion(char pali_array[], int count);
int is_palindrome(char pali_array[], int count);

int main(void){
    char c;
    int flag;
    int count = 0;
    char pali_array[30];

    // 正确读取输入:逐个读字符,跳过标点和空格,限制数组容量
    while( (c = getchar()) != '\n' && count < 30 ){
        if( !ispunct(c) && !isspace(c) ){
            pali_array[count] = c;
            count++;
        }
    }

    lower_conversion(pali_array, count);
    flag = Check_Pali(pali_array, count);
    if(flag == 1){
        printf("这不是回文!\n");
    } else {
        printf("这是回文!\n");
    }
    return 0;
}

int Check_Pali(char pali_array[], int count){
    if(count == 0){
        return 1; // 空输入按非回文处理,可按需调整
    }
    return is_palindrome(pali_array, count);
}

void lower_conversion(char pali_array[], int count){
    for(int i = 0; i < count; i++){
        // 转unsigned char避免tolower处理负数字符的未定义行为
        pali_array[i] = tolower((unsigned char)pali_array[i]);
    }
}

// 统一处理奇偶长度的回文判断,无需拆分函数
int is_palindrome(char pali_array[], int count){
    for(int i = 0; i < count/2; i++){
        if(pali_array[i] != pali_array[count - 1 - i]){
            return 1; // 返回1表示非回文
        }
    }
    return 0; // 返回0表示是回文
}

修复说明

  1. 修正输入逻辑:修复运算符优先级问题,只保留有效字符,限制数组写入长度,彻底避免越界。
  2. 简化回文判断:合并奇偶长度的判断逻辑,直接通过首尾镜像索引比较,逻辑清晰且无越界风险。
  3. 调用转小写函数:统一字符大小写,确保判断结果准确。
  4. 规避未定义行为:调用tolower时强制转换为unsigned char,避免处理负数字符的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 20:39:52