栈操作引发Segmentation fault问题及pop函数疑问求助
上下文
检查输入表达式合法性后,将数组传入infix2postfix函数。在比较运算符优先级时,执行while (iprec(a[i]) < sprec(top->ch ))出现Segmentation fault,添加if(top!=NULL)条件后恢复正常,但将条件改为while (iprec(a[i]) <= sprec(top->ch ))后再次触发Segmentation fault。
问题1:如何解决该Segmentation fault问题?
你的代码存在多处逻辑错误,直接引发了段错误,以下是针对性修正方案:
1. 修复运算符优先级循环的空栈判断
原循环未先判断top是否为NULL,栈空时访问top->ch会直接触发空指针解引用错误。必须将top != NULL作为循环前置条件,利用C语言短路求值特性,避免非法内存访问:
while (top != NULL && iprec(a[i]) <= sprec(top->ch))
2. 修正括号匹配逻辑
- 右括号判断错误:原代码把左括号
[、{当成了右括号,应改为对应的右括号:else if (a[i] == ')' || a[i] == ']' || a[i] == '}') - 括号处理循环重复pop:原循环内调用两次
pop(),会导致多弹出元素甚至栈提前为空,同时未区分不同类型括号的匹配关系,修正后:char target; switch(a[i]) { case ')': target = '('; break; case ']': target = '['; break; case '}': target = '{'; break; default: target = '\0'; } char c; while (top != NULL && (c = pop()) != target) { pfix[k++] = c; }
3. 修复后缀数组空间越界问题
原代码char pfix[strlen(a)];的空间不足以存储终止符\0,应多分配一个字节:
char pfix[strlen(a) + 1];
修正后的完整函数示例
void infix2postpix(char a[]) { char pfix[strlen(a) + 1]; int k = 0; for (int i = 0; a[i] != '\0'; i++) { if (Isopd(a[i])) { pfix[k++] = a[i]; } else if (Isopr(a[i]) || a[i] == '(' || a[i] == '{' || a[i] == '[') { while (top != NULL && iprec(a[i]) <= sprec(top->ch)) { pfix[k++] = pop(); } push(a[i]); } else if (a[i] == ')' || a[i] == ']' || a[i] == '}') { char target; switch(a[i]) { case ')': target = '('; break; case ']': target = '['; break; case '}': target = '{'; break; default: target = '\0'; } char c; while (top != NULL && (c = pop()) != target) { pfix[k++] = c; } } } while (top != NULL) { pfix[k++] = pop(); } pfix[k] = '\0'; printf("%s", pfix); }
问题2:为何pop函数必须检查top是否为NULL?
核心原因
当栈为空时,top指针指向NULL,此时访问top->no或top->ch属于空指针解引用,是C语言的未定义行为,必然触发Segmentation fault。pop函数中的top == NULL检查是为了提前拦截空栈弹出操作,避免非法内存访问。
你遇到“每次触发段错误”的原因
这不是编译问题,是代码逻辑错误导致非空栈场景下也会触发空栈弹出:比如原代码括号处理循环中每次调用两次pop(),当栈内只剩匹配的左括号时,第一次pop()取出左括号,第二次pop()就会处理空栈,此时top为NULL,访问top->no直接触发段错误。此外,原运算符优先级循环未判断top != NULL,栈空时直接访问top->ch也会引发错误。
内容的提问来源于stack exchange,提问作者Nishu Patel

