for循环执行中数组地址突变引发EXC_BAD_ACCESS错误求助
EXC_BAD_ACCESS错误排查与修复:C++生命游戏内存越界问题
在Mac系统VSCode搭配clang编译器环境下,代码第55行的for循环前12次执行正常,第13次时board变量内存地址从0x00007ff7bfeff310变为0x00007ff700000000,触发EXC_BAD_ACCESS错误。以下是问题分析与修复方案:
原始代码
#include<iostream> #include<cstdlib> #include<ctime> #include<cstring> // 补充memset所需头文件 using namespace std; int *dead_state (int *board, int width, int height) { memset(board, 0, (height * width) * sizeof(int)); return board; } int *random_state (int *board, int width, int height) { srand(time(0)); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { board[(x * width) + y] = rand() % 2; } } return board; } void render_board(int *board, int width, int height) { for (int x = 0; x < width + 2; x++) { cout << "-"; } cout << endl; for (int x = 0; x < width; x++) { cout << "|"; for (int y = 0; y < height; y++) { cout << ((board[(x * width) + y]) ? "#" : " "); } cout << "|" << endl; } for (int x = 0; x < width + 2; x++) { cout << "-"; } cout << endl; } int *next_board_state(int *board, int width, int height) { int new_board[width][height]; int draw_board[width][height]; dead_state(*new_board, width, height); dead_state(*draw_board, width, height); for (int x = 0; x < width * height; x++) { int alive = 0; //check right 3 if (!(x % width == width - 1)) { alive += board[x + 1]; if (!(x < width)){ alive += board[x + 1 - width]; } if (!(x >= width * height - width)) { alive += board[x + 1 + width]; } } //check left 3 if (!(x % width == 0)) { alive += board[x - 1]; if (!(x < width)){ alive += board[x - 1 - width]; } if (!(x > width * height - width)) { alive += board[x - 1 + width]; } } //check top if (!(x < width)){ alive += board[x - width]; } //check bottom if (!(x >= width * height - width)) { alive += board[x + width]; } //change board states if (board[x] == 1) { if (alive == 2 || alive == 3) { *new_board[x] = 1; } else { *new_board[x] = 0; } } else { if (alive == 3) { *new_board[x] = 1; } } *draw_board[x] = alive; } //Assign new board to board for (int x = 0; x < width * height; x++) { board[x] = *new_board[x]; if (x % width == 0) { cout << endl; } cout << *draw_board[x] << " "; } return board; } int main () { int width = 5, height = 5; int board[width][height]; dead_state(*board, width, height); random_state(*board, width, height); render_board(*board, width, height); next_board_state(*board, width, height); render_board(*board, width, height); return 0; }
问题根源分析
1. 二维数组与指针的错误转换
代码中多次将二维数组以*board的形式传递给函数,*board等价于board[0],仅指向二维数组的第一行,而非整个数组的起始地址。当函数通过该指针访问超出第一行的内存时,会导致越界。
2. 二维数组的错误下标访问
在next_board_state函数中,new_board和draw_board是二维数组,*new_board[x]的写法完全错误:
new_board[x]代表二维数组的第x行指针,当x超过height-1(比如width=5、height=5时,x=5就超出了行范围),会直接访问数组外的内存,触发地址异常。- 正确的做法是将一维索引x转换为二维坐标:
row = x / height,col = x % height,再通过new_board[row][col]访问。
3. 数组索引计算逻辑错误
random_state和render_board中使用x * width + y计算一维索引,不符合行优先存储的规则。对于int board[width][height],行索引x对应的一维偏移应为x * height + y,否则当width≠height时会直接越界。
修复后的代码
#include<iostream> #include<cstdlib> #include<ctime> #include<cstring> using namespace std; int *dead_state (int *board, int total_size) { memset(board, 0, total_size * sizeof(int)); return board; } int *random_state (int *board, int width, int height) { srand(time(0)); int total = width * height; for (int i = 0; i < total; i++) { board[i] = rand() % 2; } return board; } void render_board(int *board, int width, int height) { // 打印顶部边框 for (int i = 0; i < width + 2; i++) { cout << "-"; } cout << endl; // 打印每行内容 for (int x = 0; x < width; x++) { cout << "|"; for (int y = 0; y < height; y++) { int idx = x * height + y; cout << (board[idx] ? "#" : " "); } cout << "|" << endl; } // 打印底部边框 for (int i = 0; i < width + 2; i++) { cout << "-"; } cout << endl; } int *next_board_state(int *board, int width, int height) { int total = width * height; int new_board[width][height]; int draw_board[width][height]; // 初始化新数组为死状态 dead_state(&new_board[0][0], total); dead_state(&draw_board[0][0], total); for (int i = 0; i < total; i++) { int alive = 0; int x = i / height; // 行索引 int y = i % height; // 列索引 // 检查右侧邻居 if (y < height - 1) { alive += board[i + 1]; if (x > 0) alive += board[i + 1 - height]; if (x < width - 1) alive += board[i + 1 + height]; } // 检查左侧邻居 if (y > 0) { alive += board[i - 1]; if (x > 0) alive += board[i - 1 - height]; if (x < width - 1) alive += board[i - 1 + height]; } // 检查上方邻居 if (x > 0) { alive += board[i - height]; } // 检查下方邻居 if (x < width - 1) { alive += board[i + height]; } // 更新新状态 if (board[i] == 1) { new_board[x][y] = (alive == 2 || alive == 3) ? 1 : 0; } else { new_board[x][y] = (alive == 3) ? 1 : 0; } draw_board[x][y] = alive; } // 将新状态复制回原数组,并打印邻居数量 for (int i = 0; i < total; i++) { int x = i / height; int y = i % height; board[i] = new_board[x][y]; if (y == 0) cout << endl; cout << draw_board[x][y] << " "; } cout << endl; return board; } int main () { int width = 5, height = 5; int board[width][height]; int total = width * height; dead_state(&board[0][0], total); random_state(&board[0][0], width, height); render_board(&board[0][0], width, height); next_board_state(&board[0][0], width, height); render_board(&board[0][0], width, height); return 0; }
关键修复点
- 传递二维数组时,使用
&board[0][0]明确传递整个数组的起始地址。 - 统一一维索引与二维坐标的转换逻辑,避免越界访问。
- 修正
dead_state函数参数,直接传递总元素数,减少计算错误。 - 调整邻居检查的边界条件,基于行列索引判断而非一维索引,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Vilyanare
相关产品推荐
相关产品推荐

