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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:05:30