C语言实现国际象棋骑士合法移动数组程序崩溃求助
骑士合法移动函数的错误分析与修复
核心崩溃原因:空指针解引用
在validKnightMoves函数中,你仅分配了三维数组的前两层(chessPosArray***和chessPosArray**),但每个arr[i][j](chessPosArray*类型指针)并未指向有效的chessPosArray结构体。直接在checkKnightMoves中使用arrptr[row][col]->positions会触发空指针解引用,这是程序崩溃(退出码-1073741819)的根本原因。
其他关键问题
- 坐标范围判断错误:代码中
row/col是0-based索引(0-7对应棋盘8行8列),但你用newx > 0 && newx <=8的条件,会错误排除0索引对应的合法位置(如棋盘第1行)。正确范围应为newx >=0 && newx <8、newy >=0 && newy <8。 - 内存分配逻辑错误:
realloc返回值未保存:realloc可能返回新内存地址,直接调用不赋值会导致内存泄漏或访问失效内存。- 扩容条件错误:
counter > physicalsize会导致扩容不及时,应改为counter >= physicalsize(当元素数等于物理容量时扩容)。
- 缓冲区溢出风险:
chessPos定义为char[2],但sprintf写入两个字符时会自动添加终止符'\0',超出数组容量。直接赋值字符更安全。 - 内存大小计算不准确:第一层和第二层分配时,未明确指向指针的大小,需修正为对应指针类型的大小。
修正后的代码
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> // 改为char[3]以容纳字符串终止符,避免溢出 typedef char chessPos[3]; typedef struct _chessPosArray { unsigned int size; chessPos* positions; } chessPosArray; chessPosArray*** validKnightMoves(); void checkKnightMoves(chessPosArray*** arrptr, int row, int col); int main() { chessPosArray ***arr = validKnightMoves(); // 0-based索引中,第3行第3列对应arr[2][2] printf("%d\n", arr[2][2]->size); // 释放内存,避免泄漏 for(int i=0; i<8; i++){ for(int j=0; j<8; j++){ free(arr[i][j]->positions); free(arr[i][j]); } free(arr[i]); } free(arr); return 0; } chessPosArray*** validKnightMoves() { // 分配第一层:8个指向指针数组的指针 chessPosArray*** arr = malloc(sizeof(chessPosArray**) * 8); if (arr == NULL) { printf("allocation failure"); exit(1); } for(int i = 0; i < 8; i++) { // 分配第二层:每行对应8个指向结构体的指针 arr[i] = malloc(sizeof(chessPosArray*) * 8); if (arr[i] == NULL) { printf("allocation failure"); exit(1); } } for (int i = 0; i < 8; i++) { for(int j = 0; j < 8; j++) { checkKnightMoves(arr, i, j); } } return arr; } void checkKnightMoves (chessPosArray *** arrptr, int row, int col) { int newx, newy; int counter = 0; int physicalsize = 1; int dx[8] = { 2, 2, 1, 1, -1, -1, -2, -2 }; int dy[8] = { 1, -1, 2, -2, 2, -2, 1, -1 }; // 先分配chessPosArray结构体本身 arrptr[row][col] = malloc(sizeof(chessPosArray)); if (arrptr[row][col] == NULL) { printf("allocation failure"); exit(1); } // 分配初始的positions数组 arrptr[row][col]->positions = malloc(sizeof(chessPos) * physicalsize); if (arrptr[row][col]->positions == NULL) { printf("allocation failure"); exit(1); } for(int i = 0; i < 8; i++) { newx = row + dx[i]; newy = col + dy[i]; // 正确的0-based范围判断 if(newx >= 0 && newy >= 0 && newx < 8 && newy < 8) { if(counter >= physicalsize) { // 保存realloc返回的新地址 chessPos* temp = realloc(arrptr[row][col]->positions, sizeof(chessPos) * physicalsize * 2); if (temp == NULL) { printf("reallocation failure"); exit(1); } arrptr[row][col]->positions = temp; physicalsize *= 2; } // 直接赋值字符,避免缓冲区溢出 arrptr[row][col]->positions[counter][0] = 'A' + newx; arrptr[row][col]->positions[counter][1] = '1' + newy; arrptr[row][col]->positions[counter][2] = '\0'; // 添加字符串终止符 counter++; } } arrptr[row][col]->size = counter; }
修正说明
- 新增
chessPosArray结构体的内存分配,解决空指针解引用问题。 - 修正坐标范围判断,适配0-based索引逻辑。
- 修复
realloc使用方式,保存返回的新内存地址。 - 改为直接赋值字符,消除缓冲区溢出风险。
- 添加内存释放逻辑,避免内存泄漏。
- 主函数中调整索引为
arr[2][2],对应0-based的第3行第3列。
内容的提问来源于stack exchange,提问作者astralvampx
相关产品推荐
相关产品推荐

