C语言游戏开发:如何修改malloc分配的char** map数组的值?
问题描述
我正在用C语言开发一款游戏,地图内包含玩家和目标点,玩家到达目标点即为胜利。玩家每次移动时,地图会随机出现地板塌陷(用字符'X'表示)阻挡玩家。我需要更新map[i][j]的值并重新打印地图,尝试通过XGenerater函数修改char** map,使用memcpy更新pRefreshParams中的map时出现段错误(core dumped)。此前尝试在其他函数中向char** map放置对象,玩家移动后地图上会显示一个'X',但该'X'会随机跳跃。我的问题是:如何正确修改char** map的值?
原始代码
#include <stdlib.h> // 假设以下宏已预先定义:IDX_MAP_NROW, IDX_MAP_NCOL, ARR_SIZE_OBJ, GS_NONE_GOAL, GS_PLAYER_GOAL, FALSE char** createMap(int pMapSize[]) { int sizeRow = pMapSize[IDX_MAP_NROW]; int sizeCol = pMapSize[IDX_MAP_NCOL]; char** map = malloc(sizeRow * sizeof(char*)); int i = 0; for(i = 0; i < sizeRow; i++) map[i] = malloc(sizeCol * sizeof(char)); return map; } void XGenerater(char** map, const int sizeRow, const int sizeCol){ void initRandom(); int row, col; do { row = random(0, sizeRow - 1); col = random(0, sizeCol - 1); }while (map[row][col] != ' '); map[row][col] = 'X'; } int moving(void* pRefreshParams[], char cUserInput) { int gameStatus = GS_NONE_GOAL; int aiPlayerCp[ARR_SIZE_OBJ]; char* aiMapCp[2]; char** map; int *pMapSize, *pGoal, *pPlayer; unpackRefreshParams(pRefreshParams, &map, &pMapSize, &pGoal, &pPlayer); copyObj(aiPlayerCp, pPlayer); /*memcpy(aiMapCp, map, sizeof(char)*ARR_SIZE_OBJ);*/ copyMap(aiMapCp, map); performMove(aiPlayerCp, pMapSize, cUserInput); XGenerater(aiMapCp, pMapSize[IDX_MAP_NROW], pMapSize[IDX_MAP_NCOL]); copyObj(pPlayer, aiPlayerCp); /*memcpy(map, aiMapCp, sizeof(char)*ARR_SIZE_OBJ);*/ /*copyMap(map, aiMapCp);*/ if (pPlayer[IDX_COL] == pGoal[IDX_COL] && pPlayer[IDX_ROW] == pGoal[IDX_ROW]) { refreshMap(pRefreshParams); gameStatus = GS_PLAYER_GOAL; } return gameStatus; }
问题修复方案
1. 修复地图副本的内存分配错误
原始代码中char* aiMapCp[2]是固定长度的指针数组,无法适配任意行数的地图,会直接导致数组越界和野指针问题。需改为动态创建与原地图尺寸一致的副本:
// 替换原aiMapCp定义 char** aiMapCp = createMap(pMapSize);
2. 实现正确的地图复制逻辑
memcpy直接复制二级指针只会复制指针地址,而非实际地图内容。必须遍历每一行,逐行复制字符数组:
// 补充正确的copyMap函数实现 void copyMap(char** dest, char** src, int rowCount, int colCount){ for(int i = 0; i < rowCount; i++){ memcpy(dest[i], src[i], colCount * sizeof(char)); } } // 在moving函数中调用时传入尺寸参数 copyMap(aiMapCp, map, pMapSize[IDX_MAP_NROW], pMapSize[IDX_MAP_NCOL]);
3. 修正随机数初始化逻辑
在XGenerater开头调用initRandom(),确保随机数生成器正确初始化,避免因随机数序列重复导致的'X'位置异常跳跃:
void XGenerater(char** map, const int sizeRow, const int sizeCol){ void initRandom(); int row, col; initRandom(); // 初始化随机数生成器 do { row = random(0, sizeRow - 1); col = random(0, sizeCol - 1); }while (map[row][col] != ' '); map[row][col] = 'X'; }
4. 修复函数嵌套问题
C语言不支持函数嵌套定义,需将moving函数从XGenerater内部移出,保证代码语法合法。
5. 添加内存释放与地图回写
使用完动态创建的aiMapCp后,需逐行释放内存避免泄漏,并将修改后的副本内容回写至原地图:
// 在moving函数中添加 copyMap(map, aiMapCp, pMapSize[IDX_MAP_NROW], pMapSize[IDX_MAP_NCOL]); // 释放aiMapCp内存 for(int i = 0; i < pMapSize[IDX_MAP_NROW]; i++){ free(aiMapCp[i]); } free(aiMapCp);
修正后的完整核心代码
#include <stdlib.h> #include <string.h> // 假设宏定义已存在 #define IDX_MAP_NROW 0 #define IDX_MAP_NCOL 1 #define ARR_SIZE_OBJ 2 #define GS_NONE_GOAL 0 #define GS_PLAYER_GOAL 1 #define FALSE 0 char** createMap(int pMapSize[]) { int sizeRow = pMapSize[IDX_MAP_NROW]; int sizeCol = pMapSize[IDX_MAP_NCOL]; char** map = malloc(sizeRow * sizeof(char*)); int i = 0; for(i = 0; i < sizeRow; i++) map[i] = malloc(sizeCol * sizeof(char)); return map; } void initRandom(){ srand((unsigned int)time(NULL)); // 示例随机数初始化实现 } int random(int min, int max){ return min + rand() % (max - min + 1); } void XGenerater(char** map, const int sizeRow, const int sizeCol){ initRandom(); int row, col; do { row = random(0, sizeRow - 1); col = random(0, sizeCol - 1); }while (map[row][col] != ' '); map[row][col] = 'X'; } void copyMap(char** dest, char** src, int rowCount, int colCount){ for(int i = 0; i < rowCount; i++){ memcpy(dest[i], src[i], colCount * sizeof(char)); } } // 假设以下函数已实现 void unpackRefreshParams(void* p[], char*** map, int** size, int** goal, int** player){} void copyObj(int dest[], int src[]){} void performMove(int player[], int* size, char input){} void refreshMap(void* p[]){} int moving(void* pRefreshParams[], char cUserInput) { int gameStatus = GS_NONE_GOAL; int aiPlayerCp[ARR_SIZE_OBJ]; char** aiMapCp; char** map; int *pMapSize, *pGoal, *pPlayer; unpackRefreshParams(pRefreshParams, &map, &pMapSize, &pGoal, &pPlayer); copyObj(aiPlayerCp, pPlayer); aiMapCp = createMap(pMapSize); copyMap(aiMapCp, map, pMapSize[IDX_MAP_NROW], pMapSize[IDX_MAP_NCOL]); performMove(aiPlayerCp, pMapSize, cUserInput); XGenerater(aiMapCp, pMapSize[IDX_MAP_NROW], pMapSize[IDX_MAP_NCOL]); copyObj(pPlayer, aiPlayerCp); copyMap(map, aiMapCp, pMapSize[IDX_MAP_NROW], pMapSize[IDX_MAP_NCOL]); // 释放临时地图内存 for(int i = 0; i < pMapSize[IDX_MAP_NROW]; i++){ free(aiMapCp[i]); } free(aiMapCp); if (pPlayer[IDX_COL] == pGoal[IDX_COL] && pPlayer[IDX_ROW] == pGoal[IDX_ROW]) { refreshMap(pRefreshParams); gameStatus = GS_PLAYER_GOAL; } return gameStatus; }
内容的提问来源于stack exchange,提问作者Martin Chan
相关产品推荐
相关产品推荐

