C语言双栈实现队列pop2函数运行异常无报错问题
问题根因
程序崩溃的核心原因是未初始化的野指针访问,属于典型的C语言内存非法操作:
pop2函数中声明的struct stack *lol是局部指针变量,声明后没有为它分配struct stack类型的实际内存空间,指针指向随机的非法内存地址。第一行printf("!")执行时还没有触碰这个野指针所以可以正常输出,执行到lol->top1=-1时,程序尝试向非法内存地址写入数据,直接触发段错误崩溃,后续代码根本没有执行机会。- 观察到只有第一个
!输出,是因为C语言标准输出默认是行缓冲模式:不带换行符的打印内容会先暂存在内存缓冲区里,等攒够一行或者程序正常退出时才会刷到屏幕上。程序崩溃时缓冲区不会自动刷新,所以后续两个printf("!")的内容根本没来得及显示,程序就已经终止了。 - 另外
main函数里的struct stack *ptr同样是未初始化的野指针,移除pop2调用后程序能运行完全是内存布局的巧合,本质还是非法操作,随时可能崩溃。
其他现存代码问题
- 函数返回值缺失:
push、pop、pop2都声明为返回int类型,但除了正常分支外,异常分支(栈满、栈空)都没有写返回值,会触发未定义行为。 - 逻辑完全缺失:当前的
pop2没有实现任何双栈实现队列的核心逻辑,结构体里定义的top1字段也没有实际用途。双栈队列的标准逻辑是:用一个栈负责入队,另一个栈负责出队,出队时如果出队栈为空,就把入队栈的所有元素依次弹出压入出队栈,此时出队栈的栈顶就是最早入队的元素。 - 内存泄漏风险:所有
malloc申请的内存使用完后没有对应free操作。
修复后完整代码
#include <stdio.h> #include <stdlib.h> // 栈结构定义,移除无实际用途的top1字段 struct stack { int top; int size; int *arr; }; // 栈判空 int isempty(struct stack *ptr) { return ptr->top == -1; } // 栈判满 int isfull(struct stack *ptr) { return ptr->top == ptr->size - 1; } // 入栈 void push(struct stack *ptr, int data) { if (isfull(ptr)) { printf("Stack is Full\n"); return; } ptr->top++; ptr->arr[ptr->top] = data; } // 出栈 int pop(struct stack *ptr) { if (isempty(ptr)) { printf("Stack is empty\n"); return -1; // 栈空返回错误标识值 } int val = ptr->arr[ptr->top]; ptr->top--; return val; } // 栈初始化函数,先为栈结构体分配内存,再初始化成员 struct stack* init_stack(int size) { struct stack *s = (struct stack*)malloc(sizeof(struct stack)); s->top = -1; s->size = size; s->arr = (int*)malloc(size * sizeof(int)); return s; } // 双栈队列的出队操作,替换原有逻辑残缺的pop2 int dequeue(struct stack *in_stack, struct stack *out_stack) { // 出队栈为空时,将入队栈所有元素倒序压入出队栈 if (isempty(out_stack)) { while (!isempty(in_stack)) { int val = pop(in_stack); push(out_stack, val); } } // 弹出出队栈栈顶即为队首元素,符合队列先进先出特性 return pop(out_stack); } // 释放栈内存,避免泄漏 void free_stack(struct stack *s) { free(s->arr); free(s); } int main() { // 初始化两个栈分别作为入队栈、出队栈 struct stack *in = init_stack(100); struct stack *out = init_stack(100); // 入队5个元素 push(in, 1); push(in, 2); push(in, 3); push(in, 4); push(in, 5); // 依次出队,将按1 2 3 4 5的顺序输出 printf("%d ", dequeue(in, out)); printf("%d ", dequeue(in, out)); printf("%d ", dequeue(in, out)); printf("%d ", dequeue(in, out)); printf("%d ", dequeue(in, out)); // 释放申请的内存 free_stack(in); free_stack(out); return 0; }
修复要点说明
- 所有栈指针使用前,必须先为
struct stack结构体本身分配内存,不能直接声明指针就操作成员,从根源避免野指针。 - 把原有逻辑残缺的
pop2替换为符合双栈队列逻辑的dequeue函数,真正实现队列先进先出的特性。 - 补全所有函数的返回逻辑,避免无返回值的未定义行为。
- 增加栈初始化、内存释放的工具函数,保证内存操作合法,避免泄漏。
- 调试打印如果需要即时看到输出,可以加换行符或者手动刷新缓冲区,避免崩溃时看不到打印内容。
内容的提问来源于stack exchange,提问作者Bharat Goyal
相关产品推荐
相关产品推荐

