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

游戏关卡背景绘制代码出现内存访问违规错误求助

解决"Access violation writing location"内存访问错误

我帮你梳理下问题的根源,主要是内存分配的维度不匹配和数组索引逻辑错误导致的越界访问,咱们一步步来修复:

1. 内存分配的核心错误

先看你最初和修改后的内存分配代码,都存在几个关键问题:

错误点1:二维指针第一维的类型错误

二维指针crate**本质是"指向指针的指针",所以第一维应该分配的是crate*类型的数组,而不是crate结构体的数组。你最初的代码用了sizeof(crate),修改后的虽然改成了sizeof(crate*),但第一维的大小计算完全错误。

错误点2:循环边界的<=导致越界

数组索引是从0开始的,比如如果纵向有rows = SCREEN_HEIGHT / GrassBlock->h行,那么循环应该是i < rows,而不是i <= rows——后者会多循环一次,访问超出分配范围的内存。

错误点3:行列维度不匹配

二维数组的第一维对应行数(纵向),第二维对应列数(横向),你需要先明确计算这两个值,再对应分配内存。

修正后的内存分配代码

// 先计算行列数:横向列数、纵向行数
int cols = SCREEN_WIDTH / GrassBlock->w;
int rows = SCREEN_HEIGHT / GrassBlock->h;

// 第一维:分配rows个指向crate的指针
crate **Crates = (crate**)malloc(sizeof(crate*) * rows);
if (!Crates) {
    // 内存分配失败的处理逻辑,比如返回错误
    fprintf(stderr, "Failed to allocate memory for Crates rows\n");
    return 1;
}

// 第二维:为每一行分配cols个crate结构体
for (int i = 0; i < rows; i++) {
    Crates[i] = (crate*)malloc(sizeof(crate) * cols);
    if (!Crates[i]) {
        // 分配失败时要释放已分配的内存,避免泄漏
        fprintf(stderr, "Failed to allocate memory for Crates row %d\n", i);
        for (int j = 0; j < i; j++) {
            free(Crates[j]);
        }
        free(Crates);
        return 1;
    }
}

2. DrawLevelBG函数的索引逻辑错误

你在函数里用计数器i作为二维数组Obstacles的第一维索引,这完全是错误的:i会随着障碍物数量不断递增,很快就会超出数组的第一维长度(也就是行数),直接触发内存访问违规。

正确的做法是根据当前的x和y坐标,计算对应的行索引和列索引,用这两个索引来访问二维数组。

修正后的DrawLevelBG函数

int DrawLevelBG(SDL_Surface *screen, SDL_Surface *sprite, SDL_Surface *border, crate **Obstacles) {
    int x = 0;
    int y = 0;
    int obstacleCount = 0;
    // 提前计算行列数,和内存分配时保持一致
    int cols = SCREEN_WIDTH / sprite->w;
    int rows = SCREEN_HEIGHT / sprite->h;

    while (y < SCREEN_HEIGHT + sprite->h) {
        DrawSurface(screen, sprite, x + (sprite->w / 2), y + (sprite->h / 2));
        
        // 判断是否是边界砖块
        bool isBorder = (x >= SCREEN_WIDTH - sprite->w) || (x == 0) || (y == 0) || (y >= SCREEN_HEIGHT - sprite->h);
        
        if (isBorder) {
            DrawSurface(screen, border, x + (sprite->w / 2), y + (sprite->h / 2));
            
            // 计算当前砖块对应的行和列索引
            int currentRow = y / sprite->h;
            int currentCol = x / sprite->w;
            
            // 先检查索引是否在数组范围内,避免越界
            if (currentRow >= 0 && currentRow < rows && currentCol >= 0 && currentCol < cols) {
                Obstacles[currentRow][currentCol].x = x;
                Obstacles[currentRow][currentCol].y = y;
                Obstacles[currentRow][currentCol].h = border->h;
                Obstacles[currentRow][currentCol].w = border->w;
                Obstacles[currentRow][currentCol].type = WALL;
                obstacleCount++;
            }
        }

        // 处理坐标移动逻辑,简化原来的condition变量
        if (x >= SCREEN_WIDTH - sprite->w) {
            y += sprite->h;
            x = 0;
        } else {
            x += sprite->w;
        }
    }
    return obstacleCount;
}

3. 额外注意事项

  • 内存分配后一定要检查是否成功(!Crates或!Crates[i]),避免空指针访问。
  • 当不再使用二维数组时,要记得逐层释放内存:先释放每一行的Crates[i],再释放Crates本身。
  • 确保SCREEN_WIDTH和SCREEN_HEIGHT能被砖块的宽高整除,否则边缘会有未覆盖的区域,也可能导致索引计算错误。

内容的提问来源于stack exchange,提问作者Jkee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:25:21