运行Curses游戏代码时出现Segmentation Fault (core dumped)错误求助
Curses游戏Segmentation Fault问题排查
我正在开发一个基于Curses的Linux终端游戏,执行命令./escape 7 8 1 1 5 3时频繁触发Segmentation Fault (core dumped)错误。代码编译无异常,命令行参数数量(共6个)也正确,但自行调试无法定位根源,求协助排查。
原代码
#ifndef MY_GAME_H #define MY_GAME_H #include <stdio.h> #include <stdlib.h> #include <time.h> #include <curses.h> #define EMPTY ' ' #define BORDER '*' #define PLAYER 'P' #define GOAL 'G' #define COLLAPSED 'X' typedef struct position { int row; int col; } Position; typedef struct node { Position pos; char collapsed_color; struct node* next; } Node; typedef struct list { Node* head; int size; } List; int ROW, COL; char** map; Position player, goal; List history; void initialize() { int i, j; map = (char**)malloc(ROW * sizeof(char*)); for (i = 0; i < ROW; i++) { map[i] = (char*)malloc(COL * sizeof(char)); for (j = 0; j < COL; j++) { if (i == 0 || i == ROW - 1 || j == 0 || j == COL - 1) { map[i][j] = BORDER; } else { map[i][j] = EMPTY; } } } if (history.size > 0) { player = history.head->pos; goal = history.head->next->pos; } else { // initialize player and goal to default values player.row = 1; player.col = 1; goal.row = ROW - 2; goal.col = COL - 2; } map[player.row][player.col] = PLAYER; map[goal.row][goal.col] = GOAL; } void print_map() { int i, j; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { if (i == player.row && j == player.col) { attron(COLOR_PAIR(1)); printw("%c ", map[i][j]); attroff(COLOR_PAIR(1)); } else if (i == goal.row && j == goal.col) { attron(COLOR_PAIR(2)); printw("%c ", map[i][j]); attroff(COLOR_PAIR(2)); } else if (map[i][j] == COLLAPSED) { if (i == history.head->pos.row && j == history.head->pos.col) { attron(COLOR_PAIR(3)); printw("%c ", map[i][j]); attroff(COLOR_PAIR(3)); } else { printw("%c ", map[i][j]); } } else { printw("%c ", map[i][j]); } } printw("\n"); } } void collapse_floor() { int i, j; Node* new_node = (Node*)malloc(sizeof(Node)); new_node->collapsed_color = 'r'; do { new_node->pos.row = rand() % (ROW - 2) + 1; new_node->pos.col = rand() % (COL - 2) + 1; } while (map[new_node->pos.row][new_node->pos.col] != EMPTY); new_node->next = history.head; history.head = new_node; history.size++; map[new_node->pos.row][new_node->pos.col] = COLLAPSED; } void move_player(int row_offset, int col_offset) { if (map[player.row + row_offset][player.col + col_offset] == EMPTY) { map[player.row][player.col] = EMPTY; player.row += row_offset; player.col += col_offset; map[player.row][player.col] = PLAYER; collapse_floor(); } else if (map[player.row + row_offset][player.col + col_offset] == GOAL){ map[player.row][player.col] = EMPTY; player.row += row_offset; player.col += col_offset; map[player.row][player.col] = PLAYER; print_map(); printf("\nYou Win!\n"); exit(0); } } void undo_move() { if (history.size > 1) { Node* old_node = history.head; history.head = history.head->next; history.size--; if (map[player.row][player.col] == COLLAPSED) { map[player.row][player.col] = EMPTY; } player = history.head->pos; if (map[player.row][player.col] == COLLAPSED) { map[player.row][player.col] = PLAYER; map[old_node->pos.row][old_node->pos.col] = COLLAPSED; } else { map[player.row][player.col] = PLAYER; if (map[old_node->pos.row][old_node->pos.col] == COLLAPSED) { map[old_node->pos.row][old_node->pos.col] = EMPTY; } map[old_node->pos.row][old_node->pos.col] = COLLAPSED; } free(old_node); } } void end_game() { printf("Game over!\n"); exit(0); // Terminate the program with exit status 0 (success) } int main(int argc, char* argv[]) { int i; srand(time(NULL)); if (argc != 7) { printf("Usage: ./game ROW COL player_row player_col goal_row goal_col\n"); exit(1); } ROW = atoi(argv[1]); COL = atoi(argv[2]); player.row = atoi(argv[3]); player.col = atoi(argv[4]); goal.row = atoi(argv[5]); goal.col = atoi(argv[6]); if (player.row < 0 || player.row >= ROW || player.col < 0 || player.col >= COL || goal.row < 0 || goal.row >= ROW || goal.col < 0 || goal.col >= COL) { printf("Invalid player or goal position.\n"); exit(1); } history.head = (Node*)malloc(sizeof(Node)); history.head->pos = player; history.head->collapsed_color = 'r'; history.head->next = NULL; history.size = 1; initscr(); start_color(); init_pair(1, COLOR_BLUE, COLOR_BLACK); init_pair(2, COLOR_YELLOW, COLOR_BLACK); init_pair(3, COLOR_RED, COLOR_BLACK); initialize(); print_map(); while (1) { int ch = getch(); switch (ch) { case 'w': move_player(-1, 0); break; case 'a': move_player(0, -1); break; case 's': move_player(1, 0); break; case 'd': move_player(0, 1); break; case 'u': undo_move(); break; case 'q': end_game(); break; } if (player.row == goal.row && player.col == goal.col) { end_game(); } print_map(); } endwin(); for (i = 0; i < ROW; i++) { free(map[i]); } free(map); while (history.size > 0) { undo_move(); } return 0; } #endif /* MY_GAME_H */
核心错误根源
- 空指针解引用(直接触发段错误):
initialize函数中,history.size > 0分支直接访问history.head->next->pos,但main初始化history时仅创建了一个节点,next为NULL,导致空指针解引用。 print_map的空指针风险:
多次执行undo_move后,history.head可能变为NULL,此时访问history.head->pos会触发段错误。map越界访问:move_player未检查目标位置是否为边界,玩家向边界移动时会访问map的非法索引。- Curses与标准输出冲突:
end_game和胜利逻辑使用printf输出,Curses初始化后应使用printw,printf会破坏Curses的屏幕缓冲区,引发异常。
关键修复代码
修正
initialize的指针访问:void initialize() { int i, j; map = (char**)malloc(ROW * sizeof(char*)); for (i = 0; i < ROW; i++) { map[i] = (char*)malloc(COL * sizeof(char)); for (j = 0; j < COL; j++) { if (i == 0 || i == ROW - 1 || j == 0 || j == COL - 1) { map[i][j] = BORDER; } else { map[i][j] = EMPTY; } } } // 直接使用main中初始化的player和goal,避免空指针访问 map[player.row][player.col] = PLAYER; map[goal.row][goal.col] = GOAL; }print_map添加空指针判断:else if (map[i][j] == COLLAPSED) { if (history.head != NULL && i == history.head->pos.row && j == history.head->pos.col) { attron(COLOR_PAIR(3)); printw("%c ", map[i][j]); attroff(COLOR_PAIR(3)); } else { printw("%c ", map[i][j]); } }move_player添加边界检查:void move_player(int row_offset, int col_offset) { int new_row = player.row + row_offset; int new_col = player.col + col_offset; // 检查是否越界或碰到边界 if (new_row <= 0 || new_row >= ROW-1 || new_col <=0 || new_col >= COL-1) { return; } if (map[new_row][new_col] == EMPTY) { map[player.row][player.col] = EMPTY; player.row = new_row; player.col = new_col; map[player.row][player.col] = PLAYER; collapse_floor(); } else if (map[new_row][new_col] == GOAL){ map[player.row][player.col] = EMPTY; player.row = new_row; player.col = new_col; map[player.row][player.col] = PLAYER; print_map(); printw("\nYou Win!\n"); refresh(); endwin(); exit(0); } }修正
end_game输出方式:void end_game() { printw("Game over!\n"); refresh(); endwin(); exit(0); }
内容的提问来源于stack exchange,提问作者Necro007
相关产品推荐
相关产品推荐

