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
问题根源分析
main函数输入逻辑完全错误
- 运算符优先级错误:
while((c=getchar()!='\n'))实际是把getchar()!='\n'的布尔值(0或1)赋值给c,而非输入字符。正确写法应为while( (c = getchar()) != '\n' )。 - 嵌套for循环无意义:会将同一个字符重复写入数组30次,直接导致
count异常增大,后续数组访问越界。 - 跳过标点空格的逻辑错误:当前逻辑会在写入数组后再回退索引,容易引发索引混乱。
- 运算符优先级错误:
even_count函数索引计算错误
当输入长度为偶数时,回文比较的索引逻辑完全错误。例如长度为4(middle=2),正确的比较应为索引0 vs 3、1 vs 2,但当前代码会错误计算为2 vs 2、3 vs 1,不仅逻辑错误,还可能在长度较大时触发数组越界。其他隐性问题
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表示是回文 }
修复说明
- 修正输入逻辑:修复运算符优先级问题,只保留有效字符,限制数组写入长度,彻底避免越界。
- 简化回文判断:合并奇偶长度的判断逻辑,直接通过首尾镜像索引比较,逻辑清晰且无越界风险。
- 调用转小写函数:统一字符大小写,确保判断结果准确。
- 规避未定义行为:调用
tolower时强制转换为unsigned char,避免处理负数字符的异常。
内容的提问来源于stack exchange,提问作者Ada
相关产品推荐
相关产品推荐

