C语言栈+递归回文检测程序:奇数长度字符串识别异常求助
问题排查与修复:奇数长度回文检测失败
我仔细看了你的代码,发现问题出在递归逻辑的流程设计上,导致奇数长度的字符串在递归返回后重复执行了字符读取和比较逻辑,同时还有一个无效的终止条件。下面一步步拆解问题并给出修复方案:
核心问题分析
1. 递归返回后重复执行代码,导致错误读取字符
你的递归函数在charNum >= stringLength/2时,执行一次比较就return,但当递归返回到上一层调用时,上一层函数会继续执行if(stringLength%2) getchar();和后续的比较代码。举个例子,当输入长度为5的字符串abcba:
- 递归到
charNum=2时,跳过中间字符c,读取b和栈中的b比较,相等后return到charNum=1的调用; - 此时
charNum=1的调用会继续执行if(stringLength%2) getchar();,尝试读取不存在的字符(输入已经读完),导致程序等待输入;如果强制输入,会读取错误字符并和栈中的a比较,最终输出"Not palindrome"。
2. 无效的终止条件
if(stringLength ==1)这个判断永远不会触发,因为递归函数中的stringLength参数始终是初始输入的长度,不会随着递归调用改变,这个分支完全是多余的。
3. pop函数的未定义行为
当栈为空时,pop函数没有返回值,虽然逻辑上不会走到这里,但这会导致未定义行为,需要补充默认返回值。
修复后的代码
#include <stdio.h> #include <stdlib.h> struct c { char cha; struct c *nextPtr; }; typedef struct c Character; void push(Character **headPtr, char c) { Character *newC = malloc(sizeof(Character)); if(newC == NULL) { puts("Insufficient memory."); exit(1); // 内存分配失败时直接退出,避免后续错误 } newC->cha = c; newC->nextPtr = *headPtr; *headPtr = newC; } char pop(Character **headPtr) { if(*headPtr != NULL) { Character *tempPtr = *headPtr; char c = (*headPtr)->cha; *headPtr = (*headPtr)->nextPtr; free(tempPtr); return c; } return '\0'; // 栈为空时返回空字符,避免未定义行为 } void isPalindrome(int stringLength, int charNum) { static Character *headPtr = NULL; // 第一阶段:push前半部分字符 if(charNum < stringLength / 2) { char c = getchar(); push(&headPtr, c); isPalindrome(stringLength, charNum + 1); } // 仅在奇数长度的中间位置,跳过一次中间字符 else if(charNum == stringLength / 2 && stringLength % 2 != 0) { getchar(); isPalindrome(stringLength, charNum + 1); } // 第二阶段:比较后半部分字符 else if(charNum < stringLength) { char d = getchar(); char e = pop(&headPtr); if(d != e) { puts("Not palindrome"); exit(0); } isPalindrome(stringLength, charNum + 1); } // 所有字符处理完成,递归终止 else { return; } } int main() { int n; scanf("%d", &n); while(getchar() != '\n'); // 清除输入缓冲区的换行符 isPalindrome(n, 0); puts("Palindrome"); return 0; }
修复关键点说明
重构递归流程:
- 将递归分为三个清晰的阶段:前半部分push、奇数中间字符跳过、后半部分比较,确保每一层递归只负责自己的任务,不会重复执行代码。
- 当push完前半部分字符后,递归返回时自动进入比较阶段,每一层递归对应一对字符的比较,完美匹配回文的对称特性。
移除无效分支:删除了永远不会触发的
if(stringLength ==1)判断,改用charNum == stringLength作为递归终止条件。完善边界处理:给pop函数补充了栈为空时的返回值,在push函数中添加了内存分配失败的退出逻辑,避免潜在的错误。
统一输出信息:将main函数中的输出改为和递归中一致的"Palindrome",保持信息统一。
现在测试奇数长度的回文(比如5+abcba)和偶数长度的回文(比如4+abba)都能正确识别了。
内容的提问来源于stack exchange,提问作者Samuele B.
相关产品推荐
相关产品推荐

