You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

删除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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 10:25:34