游戏关卡背景绘制代码出现内存访问违规错误求助
解决"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
相关产品推荐
相关产品推荐

