Conway生命游戏非对称数组索引越界问题求助
康威生命游戏非对称数组崩溃问题排查与修复
核心问题现象
开发C++版康威生命游戏时遇到以下异常:
- Qt GUI中使用非对称数组(行≠列)时,程序因索引越界直接崩溃;后端
Board类设15×15时,GUI增加列数无异常,但行数超过15就崩溃,行数小于15则正常。 - 命令行测试:行数大于列数时,
check_index函数会提示索引错误但程序仍能运行;行数小于列数时,编译通过但无任何输出。
代码中的关键错误
1. 索引维度完全颠倒(最致命问题)
Board类中,m_gameboard的分配逻辑是:外层数组长度对应宽度(列数m_width),每个内层数组长度对应高度(行数m_height),即m_gameboard[x][y]中:
x是列索引(范围0~m_width-1)y是行索引(范围0~m_height-1)
但GameController::NextGeneration的循环逻辑完全颠倒,把行索引当成列索引使用,直接触发越界:
// 错误:i是行索引(对应y),却用来访问外层数组(应使用列索引) for (int i = 0; i < m_GameBoard.GetHeight(); i++) { for (int j = 0; j < m_GameBoard.GetWidth(); j++) { // 错误:active_states_detector[i][j] 用行索引访问外层数组 if (active_states_detector[i][j] == true) { // 错误:把行i、列j传给check_neighborhood的x、y,参数顺序完全颠倒 if (m_GameBoard.check_neighborhood(i, j) != 3 and m_GameBoard.check_neighborhood(i, j) != 2) m_GameBoard.temp_remove_cell(i, j); } } }
2. check_neighborhood函数缺少默认返回值
当check_index(x,y)为false时,函数无返回语句,会返回随机值,导致后续逻辑混乱:
int Board::check_neighborhood(int x, int y) { if (check_index(x, y) == true) { // 正常计数逻辑 return counter_of_true_states; } // 无返回值,触发未定义行为 }
3. 细胞存活判断条件写法不规范
(j or i) != 0虽然逻辑等价于i != 0 || j != 0,但or作为C++逻辑或关键字可读性极差,容易和位运算混淆。
4. 内存释放函数拼写错误
deallocate_temp_gameboad应为deallocate_temp_gameboard,拼写错误会导致临时数组无法正确释放,引发内存泄漏。
修复方案
1. 修正索引维度对应关系
所有函数调用严格遵循x=列索引,y=行索引的规则,修复GameController::NextGeneration:
void GameController::NextGeneration() { m_GameBoard.copy_GameBoard_to_Temp(); bool** active_states_detector = m_GameBoard.GetGameBoard(); // 明确区分行(y)和列(x)的循环顺序 for (int y = 0; y < m_GameBoard.GetHeight(); y++) { for (int x = 0; x < m_GameBoard.GetWidth(); x++) { if (active_states_detector[x][y] == true) { if (m_GameBoard.check_neighborhood(x, y) != 3 && m_GameBoard.check_neighborhood(x, y) != 2) m_GameBoard.temp_remove_cell(x, y); } else if (active_states_detector[x][y] == false) { if (m_GameBoard.check_neighborhood(x, y) == 3) m_GameBoard.temp_add_cell(x, y); } } } m_GameBoard.print_temp_gameboard(); m_GameBoard.reset_array('G'); m_GameBoard.copy_Temp_to_Gameboard(); m_GameBoard.reset_array('T'); std::cout << std::endl << "=====================" << std::endl << std::endl; }
2. 给check_neighborhood添加默认返回值
索引无效时返回0(符合生命游戏边界细胞规则):
int Board::check_neighborhood(int x, int y) { if (check_index(x, y) == true) { int counter_of_true_states = 0; for (int i = -1; i < 2; i++) { for (int j = -1; j < 2; j++) { if (check_index(x + i, y + j) == true) { // 修正条件写法,增强可读性 if (m_gameboard[x + i][y + j] == true && (i != 0 || j != 0)) counter_of_true_states++; } } } return counter_of_true_states; } // 索引无效时返回0 return 0; }
3. 修正内存释放函数拼写
void deallocate_temp_gameboard() // 修正拼写错误 { if (m_temp_gameboard != nullptr) { for (int i = 0; i < m_width; i++) delete[] m_temp_gameboard[i]; delete[] m_temp_gameboard; } }
4. (可选)用安全容器替代原生指针
建议用std::vector<std::vector<bool>>替代bool**,避免手动内存管理漏洞:
// Board.h中替换成员变量 std::vector<std::vector<bool>> m_gameboard; std::vector<std::vector<bool>> m_temp_gameboard; // 分配数组函数简化为 void allocate_gameboard(int width, int height) { m_gameboard.assign(width, std::vector<bool>(height, false)); }
修复效果验证
修复后:
- 非对称数组(行≠列)可正常运行,无索引越界崩溃。
- 命令行测试所有行列组合均能正确输出,
check_index仅在传入无效索引时触发错误提示。
内容的提问来源于stack exchange,提问作者Jano532
相关产品推荐
相关产品推荐

