C++几乎回文程序isPalindrome调用语句未执行问题求助
问题现象
编写判断几乎回文(允许最多删除一个字符使得字符串成为回文)的C++程序时,疑似语句r = isPalindrome(str, p[0], p[1]-1);未执行,p、q对应的isPalindrome函数调用看似正常运行,程序仅打印p和q的取值后异常退出,无法定位执行流程问题,完整原始代码如下:
#include <iostream> #include<vector> using namespace std; int arr[2]; int* isPalindrome(string &s, int i, int j){ int sz = s.length(); if(i==j) return NULL; while(i<j){ if(s[i] == s[j]){ i++; j--; } else{ arr[0] = i; arr[1] = j; return arr; } } return NULL; } int main() { string s = "abcdefdba", str; int *p, *q, *r; // removes any additional character or spaces and make lower-case for(int i=0; i<s.length();i++){ if(s[i] >= 65 && s[i]<=90) str.push_back(s[i]+32); if((s[i] >=97 && s[i]<=122) || (s[i]>=48 && s[i]<=57)) str.push_back(s[i]); } p = isPalindrome(str, 0, str.length()-1); cout<<"pointer p: "<<p[0]<<p[1]<<endl; if(p==NULL) cout<<"true"; else{ q = isPalindrome(str, p[0]+1, p[1]); r = isPalindrome(str, p[0], p[1]-1); // not getting executed } cout<<"pointer q: "<<q[0]<<q[1]<<endl; cout<<"pointer r: "<<r[0]<<r[1]<<endl; if(q==NULL || r==NULL) cout<<"true"; else cout<<"false"; return 0; }
根因分析
你误以为r的赋值行未执行,实际是程序存在空指针/野指针解引用的致命问题,在执行到r相关的打印逻辑前就已经触发段错误异常退出,核心问题点如下:
- 所有指针解引用操作前没有做非空判断:只要
isPalindrome返回NULL(代表子串是回文),后续直接访问p[0]/q[0]/r[0]就会访问非法内存,触发段错误直接终止程序。比如当删除左字符后的子串是回文时,q被赋值为NULL,执行到打印q的语句时就会崩溃,根本走不到后续r的打印逻辑,看起来就像r的赋值行没跑。 - 全局数组共享内存的逻辑错误:所有非NULL的
isPalindrome返回值都指向同一个全局数组arr,后续调用会覆盖之前写入的索引值,导致p、q、r指向的内容被意外篡改,逻辑完全不符合预期。 - 指针未初始化:p、q、r定义时没有初始化为NULL,如果原串本身是回文(p==NULL),不会进入else块给q、r赋值,后续访问q、r属于野指针访问,程序行为完全不可控。
- 冗余判断:
isPalindrome里if(i==j) return NULL;是多余代码,i==j时循环条件i<j不成立,本来就会走到函数末尾返回NULL,不会影响逻辑但属于无效代码。 - 预处理逻辑可读性差:用ASCII硬编码判断字符类型,且两个if没有做互斥,虽然当前场景不会重复插入字符,但后续修改很容易引入bug。
修复方案
直接重构isPalindrome的返回值为bool类型即可,不需要用全局数组传索引,从根源避免空指针和内存共享问题,修复后代码如下:
#include <iostream> #include <string> #include <cctype> using namespace std; // 直接返回子串s[i..j]是否为回文 bool isPalindrome(string &s, int i, int j){ while(i < j){ if(s[i] != s[j]) return false; i++; j--; } return true; } int main() { string s = "abcdefdba", str; // 预处理字符串:转小写,只保留字母和数字 for(int i=0; i<s.length();i++){ if(isalpha(s[i])){ str.push_back(tolower(s[i])); }else if(isdigit(s[i])){ str.push_back(s[i]); } } int left = 0, right = str.length() - 1; bool res = true; while(left < right){ if(str[left] != str[right]){ // 遇到不匹配位置,判断删左字符或者删右字符后是否为回文 res = isPalindrome(str, left+1, right) || isPalindrome(str, left, right-1); break; } left++; right--; } cout << (res ? "true" : "false") << endl; return 0; }
内容的提问来源于stack exchange,提问作者Mohan
相关产品推荐
相关产品推荐

