C++中std::out_of_range错误排查及井字棋代码修正咨询
问题描述
我正在用C++开发井字棋(tic-tac-toe)游戏,编写的代码如下:
#include <iostream> #include <vector> bool X = true; bool O = false; bool b = true; int a = 0; int j = 100; std::string game = ""; std::vector<char> c = {'1', '2', '3', '4', '5','6','7','8','9'}; void check(){ std::cout<<"Enter position: "; int pos; std::cin>>pos; if(c.at(pos-1)==pos){ if(X == true){ c[pos-1] = 'X'; O = true; X = false; a = 0; } else if(O == true){ c[pos-1] = 'O'; X = true; O = false; a = 0; } } else{ std::cout<<"Not empty, enter again."; a = 1; } } void print(){ std::cout<<"|---|---|---| | "<<c.at(0)<<" | "<<c.at(1)<<" | "<<c.at(2)<<" | "<<"\n" "|---|---|---| | "<<c.at(3)<<" | "<<c.at(4)<<" | "<<c.at(5)<<" | "<<"\n" "|---|---|---| | "<<c.at(6)<<" | "<<c.at(7)<<" | "<<c.at(8)<<" | \n" "|---|---|---| "; } int main(){ print(); int b = 0; while((X==true||O==true)&&b<9){ check(); while(a=1){ check(); } print(); for(int i = 0;i<7;i+=3){ if(c.at(i)==c.at(i+1)&&c.at(i+1)==c.at(i+2)&&c.at(i)==c.at(i+2)){ j = i; break; } else{ continue; } } for(int i = 0;i<3;i++){ if(c.at(i)==c.at(i+3)&&c.at(i+3)==c.at(i+6)&&c.at(i)==c.at(i+6)){ j = i; break; } else{ continue; } } if(c.at(0)==c.at(4)&&c.at(4)==c.at(8)&&c.at(0)==c.at(8)){ j = 0; } else if(c.at(2)==c.at(4)&&c.at(4)==c.at(6)&&c.at(2)==c.at(6)){ j = 2; } if(j!=100){ break; } b++; } if(j!=100){ if(c.at(j)=='X'){ game = "Won by X!"; } else{ game = "Won by O!"; } } else if(j=100){ game = "Draw"; } std::cout<<game<<"\n"; }
运行时持续出现以下错误:
|---|---|---| | 1 | 2 | 3 | |---|---|---| | 4 | 5 | 6 | |---|---|---| | 7 | 8 | 9 | |---|---|---| Enter position: terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 18446744073709551615) >= this->size() (which is 9)
我编写了两个函数并在main函数的while循环中调用,循环以bool类型变量X或O为true作为执行条件。我认为错误出在第一个函数,但未发现问题。请问该如何修复这个错误?此外,我的代码其余部分是否正确?
错误修复及代码优化建议
1. 核心错误:std::out_of_range 异常修复
这个异常是因为访问了vector的非法索引(18446744073709551615是无符号的-1,说明pos-1变成了负数),根源有两点:
- 输入验证缺失:用户输入非整数(字母、符号)时,
std::cin >> pos会失败,pos变成垃圾值,导致c.at(pos-1)越界。 - 位置判断错误:
c里存的是字符'1'-'9',直接对比c.at(pos-1)==pos是错的(字符和整数的ASCII值不匹配)。
修复后的check()函数:
void check(){ std::cout << "Enter position: "; int pos; // 强制输入1-9的整数,处理非法输入 while(!(std::cin >> pos) || pos < 1 || pos > 9){ std::cin.clear(); // 重置输入流错误状态 std::cin.ignore(1000, '\n'); // 跳过当前行的无效输入 std::cout << "无效输入!请输入1-9之间的数字:"; } // 正确判断位置是否未被占用:字符转数字对比 if(c.at(pos-1) == '0' + pos){ if(X){ c[pos-1] = 'X'; X = false; O = true; a = 0; } else if(O){ c[pos-1] = 'O'; O = false; X = true; a = 0; } } else { std::cout << "该位置已被占用,请重新输入。\n"; a = 1; } }
2. 其他代码问题修复
(1)循环条件的赋值错误
main函数里的while(a=1)是赋值操作,会导致循环永远为真,必须改成判断:while(a == 1)。
(2)三连判断冗余
检查胜负的代码里,c.at(i)==c.at(i+1)&&c.at(i+1)==c.at(i+2)&&c.at(i)==c.at(i+2)最后一个判断完全多余,简化为c.at(i)==c.at(i+1) && c.at(i+1)==c.at(i+2)即可。
(3)平局判断的赋值错误
else if(j=100)是赋值操作,应该改成else if(j == 100)。
(4)全局变量滥用
全局变量X、O、a、j、c容易导致逻辑混乱,建议改成局部变量或通过参数传递,比如把棋盘和回合状态作为参数传给函数。
(5)循环条件冗余
main里的while((X==true||O==true)&&b<9)可以简化为while(j == 100 && b < 9),因为只要没分出胜负(j还是100)且没下满9步就继续。
3. 优化后的完整代码示例
#include <iostream> #include <vector> #include <limits> // 打印棋盘 void print(const std::vector<char>& board){ std::cout << "|---|---|---|\n" << "| " << board[0] << " | " << board[1] << " | " << board[2] << " |\n" << "|---|---|---|\n" << "| " << board[3] << " | " << board[4] << " | " << board[5] << " |\n" << "|---|---|---|\n" << "| " << board[6] << " | " << board[7] << " | " << board[8] << " |\n" << "|---|---|---|\n"; } // 检查是否获胜 bool checkWin(const std::vector<char>& board){ // 检查行 for(int i = 0; i < 9; i += 3){ if(board[i] == board[i+1] && board[i+1] == board[i+2]){ return true; } } // 检查列 for(int i = 0; i < 3; ++i){ if(board[i] == board[i+3] && board[i+3] == board[i+6]){ return true; } } // 检查对角线 if(board[0] == board[4] && board[4] == board[8]){ return true; } if(board[2] == board[4] && board[4] == board[6]){ return true; } return false; } // 玩家落子 void makeMove(std::vector<char>& board, bool& isXTurn){ int pos; std::cout << "请输入位置:"; while(!(std::cin >> pos) || pos < 1 || pos > 9 || board[pos-1] != '0' + pos){ if(!std::cin){ std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cout << "无效输入!请输入1-9之间的数字:"; } else if(board[pos-1] != '0' + pos){ std::cout << "该位置已被占用,请重新输入:"; } else { std::cout << "请输入1-9之间的数字:"; } } board[pos-1] = isXTurn ? 'X' : 'O'; isXTurn = !isXTurn; } int main(){ std::vector<char> board = {'1', '2', '3', '4', '5','6','7','8','9'}; bool isXTurn = true; int moves = 0; bool gameWon = false; print(board); while(moves < 9 && !gameWon){ makeMove(board, isXTurn); print(board); gameWon = checkWin(board); moves++; } if(gameWon){ std::cout << (isXTurn ? "O" : "X") << "获胜!\n"; } else { std::cout << "平局!\n"; } return 0; }
内容的提问来源于stack exchange,提问作者Asteria
相关产品推荐
相关产品推荐

