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

如何使用ncurses在窗口中打印从命名管道读取的迷宫矩阵?

问题分析与修复方案

核心问题:窗口被提前销毁

代码中创建janelaTopo后,过早执行了delwin(janelaTopo);,直接销毁了顶部窗口。后续读取管道时再用这个无效指针操作窗口,属于非法内存访问,自然无法显示内容。

具体修复步骤

1. 调整窗口生命周期

将窗口销毁代码移到读取管道并显示迷宫之后,也就是endwin()之前。修改后main函数的核心结构如下:

int main(int argc, char *argv[])
{
    // ... 参数检查、ncurses初始化、窗口创建代码 ...

    writeMap(janelaTopo, 2);
    wprintw(janelaBaixo, "Linha de Comandos\n");
    writeMap(janelaBaixo, 1);
    trataTeclado(janelaTopo, janelaBaixo);
    wrefresh(janelaTopo);
    // 此处不要删除窗口

    // ... 管道读写代码 ...

    // 迷宫显示完成后再销毁窗口
    delwin(janelaTopo);
    wclear(janelaBaixo);
    wrefresh(janelaBaixo);
    delwin(janelaBaixo);

    endwin();
    return 0;
}

2. 修正函数调用笔误

你定义的窗口绘制函数是writeMap,但代码中调用的是desenhaMapa,这会导致编译错误或异常行为,统一函数名:

// 替换调用处的desenhaMapa为writeMap
writeMap(janelaTopo, 2);
wprintw(janelaBaixo, "Linha de Comandos\n");
writeMap(janelaBaixo, 1);

3. 替换ncurses模式下的printf

ncurses初始化后使用printf会破坏终端虚拟屏幕布局,把超时提示换成ncurses原生打印函数:

// 替换原printf语句
mvprintw(0, 0, "Timeout - Não foram recebidos dados do servidor\n");
refresh();

4. 确保迷宫绘制在窗口内部

writeMap函数绘制了窗口边框,打印迷宫时需要避开边框,将光标定位到窗口内部起始位置:

// 读取管道的循环中,先移动光标到边框内的起始位置
int row = 1; // 从边框内第一行开始
while (read(fd_servidor, linhaRecebida, sizeof(linhaRecebida)) > 0)
{
    wmove(janelaTopo, row++, 1); // 移动光标到当前行第1列
    wprintw(janelaTopo, "%s", linhaRecebida);
    wrefresh(janelaTopo);
}

5. 处理换行符问题

如果管道读取的每行末尾没有换行符,手动添加避免内容挤在一行:

wprintw(janelaTopo, "%s\n", linhaRecebida);

修复后关键代码片段

int main(int argc, char *argv[])
{

    if (argc != 2)
    {
        fprintf(stderr, "USo: %s <Nome do Jogador>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (access("cliente_servidor", F_OK) != 0)
    {
        printf("[ERRO] O 'motor' nao esta a funcionar!\n");
        exit(1);
    }

    initscr();
    raw();
    noecho();
    keypad(stdscr, TRUE);
    attrset(A_DIM);

    WINDOW *janelaTopo = newwin(30, 82, 1, 1);
    WINDOW *janelaBaixo = newwin(15, 82, 33, 1);

    writeMap(janelaTopo, 2);
    wprintw(janelaBaixo, "Linha de Comandos\n");
    writeMap(janelaBaixo, 1);
    trataTeclado(janelaTopo, janelaBaixo);
    wrefresh(janelaTopo);

    // 管道操作部分
    int fd_cliente = open("cliente_servidor", O_WRONLY);
    char nome_jogador[TAMANHO_NOME];
    strncpy(nome_jogador, argv[1], sizeof(nome_jogador));

    if (write(fd_cliente, &nome_jogador, sizeof(nome_jogador)) == -1)
    {
        perror("Erro ao escrever no FIFO no JOGOUI");
        return 1;
    }
    close(fd_cliente);

    int fd_servidor = open("servidor_cliente", O_RDONLY);
    if (fd_servidor == -1)
    {
        perror("Erro ao abrir o FIFO servidor_cliente no JOGOUI");
        return 2;
    }

    fd_set set;
    struct timeval timeout;
    FD_ZERO(&set);
    FD_SET(fd_servidor, &set);
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    int result = select(fd_servidor + 1, &set, NULL, NULL, &timeout);
    if (result == -1)
    {
        perror("Erro durante a chamada do select");
        close(fd_servidor);
        return 3;
    }
    else if (result == 0)
    {
        mvprintw(0, 0, "Timeout - Não foram recebidos dados do servidor\n");
        refresh();
    }
    else
    {
        char linhaRecebida[NCOL];
        int row = 1;
        while (read(fd_servidor, linhaRecebida, sizeof(linhaRecebida)) > 0)
        {
            wmove(janelaTopo, row++, 1);
            wprintw(janelaTopo, "%s", linhaRecebida);
            wrefresh(janelaTopo);
        }
    }

    close(fd_servidor);

    // 销毁窗口移至最后
    delwin(janelaTopo);
    wclear(janelaBaixo);
    wrefresh(janelaBaixo);
    delwin(janelaBaixo);

    endwin();
    return 0;
}

内容的提问来源于stack exchange,提问作者João Simões

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 04:37:34