C++使用for循环时出现段错误:SDL2蚂蚁模拟项目崩溃问题
问题描述
我正在使用SDL2开发一款蚂蚁模拟程序,运行代码后很快崩溃,提示段错误。我判断故障原因是代码尝试访问数组的负下标,因此添加了if语句校验蚂蚁在我以方块构建的"grid"上的位置,试图避免该问题。我在第420行新增了if语句验证我的猜想,但并未起到任何作用,请问有人能定位到问题所在吗?
我的网格结构体定义代码如下:
struct Wall { bool IsAlive; int Health = 10; SDL_Rect Rect; bool isAnt; bool IsHome; bool IsFood; };
网格初始化代码如下:
int count = 0; for (int i = 0; i < 1440; i += 4) { for (int j = 0; j < 795; j += 4) { SDL_Rect Rect = {i, j, 4, 4}; wall[count].Rect = Rect; wall[count].IsAlive = true; if (i < 10) { if (j < 10) { wall[count].IsAlive = false; } } count++; } }
蚂蚁挖掘逻辑实现代码如下:
void Break(int AntID, int SurroundingSqr /*Clockwise*/) { if (SurroundingSqr == -199) { if (A[AntID].PosID > 100) { wall[A[AntID].PosID + SurroundingSqr].Health--; if (wall[A[AntID].PosID + SurroundingSqr].Health == 0) { wall[A[AntID].PosID + SurroundingSqr].IsAlive = false; } } } else { wall[A[AntID].PosID + SurroundingSqr].Health--; if (wall[A[AntID].PosID + SurroundingSqr].Health == 0) { wall[A[AntID].PosID + SurroundingSqr].IsAlive = false; } } }
问题定位
首先计算你的网格总容量:横向i遍历步长为4,总共有1440/4=360列,纵向j步长为4,总共有199行,所以wall数组的合法下标范围是0 ~ 360*199 - 1 = 71639,只要访问下标超出这个范围就会触发段错误。
你的代码存在四个明显的崩溃风险:
- 边界校验覆盖不全:你只对
SurroundingSqr == -199的情况做了校验,其他所有取值(包括其他负数、超大正数)完全没有校验,直接计算下标访问数组,大概率触发越界。 - 现有校验逻辑错误:你校验
A[AntID].PosID > 100是无效的,要满足A[AntID].PosID + SurroundingSqr >= 0,需要PosID至少大于等于199,当PosID为101~198之间的数值时,计算出来的下标仍然是负数,你的校验拦不住。 - 缺少上边界校验:你只考虑了负下标的情况,没有校验下标是否超过数组最大长度,当蚂蚁处于网格底部附近时,加正数偏移量后下标超出71639,同样会触发越界。
- 数组容量不足风险:如果你的
wall数组初始化时分配的长度小于71640,在网格初始化阶段就已经发生越界写入,也会触发后续运行时的段错误。
修复方案
修改Break函数,每次访问前统一做上下边界校验:
// 先定义全局常量方便维护 const int GRID_COLS = 1440 / 4; const int GRID_ROWS = 795 / 4; const int GRID_TOTAL = GRID_COLS * GRID_ROWS; void Break(int AntID, int SurroundingSqr /*Clockwise*/) { int targetIdx = A[AntID].PosID + SurroundingSqr; // 统一做边界校验,合法才执行后续操作 if (targetIdx >= 0 && targetIdx < GRID_TOTAL) { wall[targetIdx].Health--; if (wall[targetIdx].Health == 0) { wall[targetIdx].IsAlive = false; } } }
如果还有逻辑异常,可以额外加行对齐校验,避免同一行的偏移跨到其他行:
// 额外校验,确保偏移后的格子和当前蚂蚁格子在同一行/相邻行,避免逻辑错误 int currentRow = A[AntID].PosID / GRID_COLS; int targetRow = targetIdx / GRID_COLS; if (abs(currentRow - targetRow) > 1) return;
内容的提问来源于stack exchange,提问作者DischordDynne
相关产品推荐
相关产品推荐

