簡體   English   中英

訪問 ncurses 中的 WINDOW 結構數組時出現分段錯誤

[英]Segmentation fault while accessing an array of WINDOW structures in ncurses

我正在使用 ncurses 制作一個小益智游戲,該游戲允許用戶點擊任何箭頭鍵來移動包含每個數字的框,所有框都在一個大框內,以升序排列數字。 它是一個 4x4 的盒子,一個子盒子是空白的,以便其他子盒子可以移動。

現在我在訪問我在函數中創建的 WINDOW 數組(不是指針)時遇到問題,以便我可以銷毀所有 sub_boxes,更改數字數組,並根據數組重新創建子框。

#include <stdio.h>
#include <ncurses.h>
#include <math.h>
#include <string.h>


#define HEIGHT 16
#define WIDTH 32
#define STARTY ((LINES - HEIGHT) / 2)
#define STARTX ((COLS - WIDTH) / 2)

#define QEXIT 81
#define qEXIT 113



WINDOW *create_win(int height, int width, int starty, int startx){
        WINDOW *local_win;

        local_win = newwin(height, width, starty, startx);
        box(local_win, 0, 0);
        wrefresh(local_win);

        return local_win;
};

void destroy_win(WINDOW *local_win){
        wborder(local_win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
        wrefresh(local_win);
        delwin(local_win);
};


void draw_list(WINDOW *local_win, WINDOW *num_wins, int arr[][4], int length){

        for(int i=0; i < length; i++){
                for(int j=0; j < length; j++){
                        refresh();
                        WINDOW *sub_win;
                        int height = HEIGHT / length, width = WIDTH / length, starty = STARTY + i*height, startx = STARTX + j*width;
                        sub_win = create_win(height, width, starty, startx);
                        //wprintw(stdscr, "%d |", sizeof(*sub_win));

                        *(num_wins + i*4+j) = *sub_win;
                        //wprintw(stdscr, "%d - ", i*4+j);
                        //overwrite(sub_win, (num_wins + i*4+j));

                        //memcpy(num_wins + i*4+j, sub_win, sizeof(*sub_win));

                        int digity = height / 2, digitx = width / 2 - 1;
                        if(arr[i][j])
                                mvwprintw(sub_win, digity, digitx, "%d ", arr[i][j]);
                        else
                                mvwprintw(sub_win, digity, digitx, "X ");

                        wrefresh(sub_win);
                };
        };
};

void destroy_list(WINDOW *num_wins){
        int length = 16;
        for(int i=0; i < length; i++){
                wprintw(stdscr, "%d ", i);
                wborder((num_wins + i), ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
                wrefresh((num_wins + i));
                delwin((num_wins + i));
        };
};

void play(){
        int arr[4][4] = {1,4,15,7,8,10,2,11,14,3,6,13,12,9,5,0};
        int length = 4;

        WINDOW *win;
        int starty, startx;

        //Placement
        starty = STARTY;
        startx = STARTX;

        printw("Press Q or q to exit\n");
        //printw("%d - %d\n%d - %d\n", LINES, COLS, HEIGHT, WIDTH);
        printw("\n");

        refresh();

        // Create original window               (Maybe it is useless)
        win = create_win(HEIGHT, WIDTH, starty, startx);

        // Create sub windows for numbers
        WINDOW sub_wins[16];
        draw_list(win, sub_wins, arr, length);

        refresh();

        getch();

        destroy_win(&sub_wins[0]);
        refresh();
        //for(int i=0; i < 16; i++){
        //      wprintw(stdscr, "%d -", sizeof(sub_wins[i]));
                //destroy_win(sub_wins + i);
        //};
        wrefresh(win);

        int ch = getch();
        while(ch != QEXIT && ch != qEXIT){
                switch(ch){
                        case KEY_UP:
                                destroy_win(win);
                                win = create_win(HEIGHT, WIDTH, --starty, startx);
                                //destroy_list(sub_wins);
                                break;
                        case KEY_RIGHT:
                                destroy_win(win);
                                win = create_win(HEIGHT, WIDTH, starty, ++startx);
                                break;
                        case KEY_DOWN:
                                destroy_win(win);
                                win = create_win(HEIGHT, WIDTH, ++starty, startx);
                                break;
                        case KEY_LEFT:
                                destroy_win(win);
                                win = create_win(HEIGHT, WIDTH, starty, --startx);
                                break;

                };
                ch = getch();
        };
};

int main(void){
        //printList(arr, length);

        printf("\n");

        // Init ncurses
        initscr();
        cbreak();
        noecho();
        keypad(stdscr, TRUE);

        // Game mechanics
        play();

        endwin();

        return 0;
};

我在代碼中提出了多個問題,有些部分與我的主要問題並不完全相關。 對不起。 但我想主要解決有關銷毀子窗口的問題。

先感謝您。

您不能將一個窗口拆分為兩個窗口。 如果復制窗口結構,則需要使用一個且僅一個實例來引用窗口。

                    *(num_wins + i*4+j) = *sub_win;

在這里你復制一個窗口。 該窗口現在位於兩個位置, sub_winnum_wins數組中。 你沒有兩個窗口,你只有一個。 所以你需要選擇其中之一。

                    if(arr[i][j])
                            mvwprintw(sub_win, digity, digitx, "%d ", arr[i][j]);
                    else
                            mvwprintw(sub_win, digity, digitx, "X ");

                    wrefresh(sub_win);

好的,所以你修改sub_win 這意味着您制作的副本不是窗口。 請記住,只有一個窗口。 由於您修改了sub_win ,因此它是窗口。 那么在修改窗口之前復制窗口有什么意義,那不再是窗口了。

void destroy_list(WINDOW *num_wins){
        int length = 16;
        for(int i=0; i < length; i++){
                wprintw(stdscr, "%d ", i);
                wborder((num_wins + i), ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
                wrefresh((num_wins + i));
                delwin((num_wins + i));
        };
};

你在這里做什么? 您正在操作修改窗口之前的窗口副本。 但是你修改了它——所以那個窗口不再存在。 這段代碼沒有意義。

窗戶是一個,而且只有一個。 如果制作WINDOW結構的副本,則可以使用任一副WINDOW表示窗口。 但是你不能同時使用兩者——只有一個窗口。 您的代碼同時使用兩者。 那是無效的。

總之:您制作了窗口的副本,然后修改了窗口(不是副本)。 這意味着該副本的窗口,是你修改了它,這東西已經存在,因為你修改你復制的東西之前的副本。 所以嘗試訪問副本是一個錯誤,因為它是一個不再存在的東西的副本。

這有點像這樣做:

  1. 你拿一張白紙。
  2. 你復制一份。
  3. 你在原紙上寫下“1”。
  4. 您嘗試擦除副本上的“1”。

復制后,您可以將任一面視為原件,因為它們一點上是相同的。 但是你也不能惹別人,否則你會非常困惑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM