删除Curses库WINDOW时触发段错误的排查与解决求助
问题:ncurses窗口删除后段错误及内容残留问题
- 在启动动画和main_menu中使用WINDOW对象,执行
delwin(win)后触发段错误 - 尝试清除窗口时,边框和“Snake”消失,但“Play、Rules、Credits、Quit”仍残留屏幕
- 倾向于删除窗口而非清除,仅在main_menu及主游戏场景使用窗口
相关代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curses.h> #include <time.h> #include <unistd.h> void main_menu(int xm, int ym); void rules(int xm, int ym); int main(){ initscr(); noecho(); curs_set(0); int xm, ym; getmaxyx(stdscr, ym, xm); WINDOW *win = newwin(ym/2, xm/2, ym/4, xm/4); box(win, 0, 0); mvwprintw(win, ym/4 - 3, xm/4 - 2, "Play"); mvwprintw(win, ym/4, xm/4 - 4, "Options"); mvwprintw(win, ym/4 + 3, xm/4 - 2, "Quit"); wrefresh(win); int anim = 2; int intro = 3; clock_t start_time; while(1){ wclear(win); box(win, 0, 0); mvwprintw(win, 0, anim, "Snake"); mvwprintw(win, ym/4, xm/4 - 5, "Loading..."); wrefresh(win); start_time = clock(); while(clock() < start_time + 30000){} if(intro == 3){ if(anim < xm/2 - 7) anim++; else intro--; } if(intro == 2){ if(anim > 2) anim--; else intro--; } if(intro == 1){ if(anim < xm/4 - 2) anim++; else intro--; } if(intro == 0) break; } wborder(win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); wrefresh(win); delwin(win); main_menu(xm, ym); endwin(); return 0; } void main_menu(int xm, int ym){ WINDOW *win = newwin(ym/2, xm/2, ym/4, xm/4); wclear(win); box(win, 0, 0); mvwprintw(win, 0, xm/4 - 2, "Snake"); wrefresh(win); keypad(win, TRUE); int selected = 1; int slider = 0; wattron(win, A_STANDOUT); mvwprintw(win, ym/4 - 4, xm/4 - 2, "Play"); wattroff(win, A_STANDOUT); mvwprintw(win, ym/4 - 1, xm/4 - 3, "Rules"); mvwprintw(win, ym/4 + 2, xm/4 - 3, "Credits"); mvwprintw(win, ym/4 + 5, xm/4 - 2, "Quit"); while(1){ slider = wgetch(win); if(slider == KEY_UP){ if(selected != 1) selected--; } if(slider == KEY_DOWN){ if(selected != 4) selected++; } if(slider == 10){ wborder(win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); wrefresh(win); delwin(win); if(selected == 2) rules(xm, ym); } switch(selected){ case 1: wattron(win, A_STANDOUT); mvwprintw(win, ym/4 - 4, xm/4 - 2, "Play"); wattroff(win, A_STANDOUT); mvwprintw(win, ym/4 - 1, xm/4 - 3, "Rules"); mvwprintw(win, ym/4 + 2, xm/4 - 3, "Credits"); mvwprintw(win, ym/4 + 5, xm/4 - 2, "Quit"); break; case 2: wattron(win, A_STANDOUT); mvwprintw(win, ym/4 - 1, xm/4 - 3, "Rules"); wattroff(win, A_STANDOUT); mvwprintw(win, ym/4 - 4, xm/4 - 2, "Play"); mvwprintw(win, ym/4 + 2, xm/4 - 3, "Credits"); mvwprintw(win, ym/4 + 5, xm/4 - 2, "Quit"); break; case 3: wattron(win, A_STANDOUT); mvwprintw(win, ym/4 + 2, xm/4 - 3, "Credits"); wattroff(win, A_STANDOUT); mvwprintw(win, ym/4 - 4, xm/4 - 2, "Play"); mvwprintw(win, ym/4 - 1, xm/4 - 3, "Rules"); mvwprintw(win, ym/4 + 5, xm/4 - 2, "Quit"); break; case 4: wattron(win, A_STANDOUT); mvwprintw(win, ym/4 + 5, xm/4 - 2, "Quit"); wattroff(win, A_STANDOUT); mvwprintw(win, ym/4 - 4, xm/4 - 2, "Play"); mvwprintw(win, ym/4 - 1, xm/4 - 3, "Rules"); mvwprintw(win, ym/4 + 2, xm/4 - 3, "Credits"); break; default: mvwprintw(win, ym/4 - 4, xm/4 - 2, "Play"); mvwprintw(win, ym/4 - 1, xm/4 - 3, "Rules"); mvwprintw(win, ym/4 + 2, xm/4 - 3, "Credits"); mvwprintw(win, ym/4 + 3, xm/4 - 2, "Quit"); break; } wrefresh(win); } } void rules(int xm, int ym){ clear(); box(win, 0, 0); // ─│╲╱ refresh(); }
问题分析与修复方案
1. 段错误原因
执行delwin(win)后,main_menu的循环仍会继续调用wgetch(win)、mvwprintw等操作已释放的窗口指针,属于访问悬空指针,直接触发段错误。另外rules函数中未定义win变量,也是潜在错误点。
2. 内容残留原因
删除窗口前仅用wborder覆盖边框,未清除窗口内的文本内容,也未刷新stdscr让底层终端更新显示。
3. 具体修复步骤
- 终止循环避免悬空指针访问:在
delwin(win)后立即break退出main_menu的while循环,防止后续代码操作已释放的窗口 - 正确清理窗口内容:删除窗口前先调用
wclear(win)清除所有内容,再wrefresh(win)同步到终端,最后执行delwin(win) - 修复rules函数:删除未定义的
win引用,改为直接操作stdscr,或者传递合法的窗口指针 - 刷新stdscr确保显示更新:删除窗口后调用
refresh()让终端彻底更新原窗口区域
修改后的关键代码片段
// main_menu中处理回车的代码块 if(slider == 10){ wclear(win); // 清除窗口所有内容 wrefresh(win); // 同步到终端 delwin(win); if(selected == 2) rules(xm, ym); break; // 退出循环,避免后续访问悬空指针 } // 修复后的rules函数 void rules(int xm, int ym){ clear(); // 清除stdscr box(stdscr, 0, 0); // 在stdscr上绘制边框 mvwprintw(stdscr, ym/2 - 5, xm/2 - 10, "游戏规则:"); mvwprintw(stdscr, ym/2 - 3, xm/2 - 15, "1. 使用方向键控制蛇的移动"); mvwprintw(stdscr, ym/2 - 1, xm/2 - 15, "2. 吃到食物后蛇身变长,得分增加"); mvwprintw(stdscr, ym/2 + 1, xm/2 - 15, "3. 碰到墙壁或自己的身体则游戏结束"); mvwprintw(stdscr, ym/2 + 3, xm/2 - 8, "按任意键返回菜单"); refresh(); getch(); // 等待按键 main_menu(xm, ym); // 返回主菜单 }
内容的提问来源于stack exchange,提问作者Trickery
相关产品推荐
相关产品推荐

