字符串迭代器传参触发EXCEPTION_WRONG_SHIP_TYPE异常求助
问题:舰队击沉游戏中
addShips函数触发舰船类型错误异常 我开发了一款舰队击沉(Sink the Fleet)小游戏,其中Player类的addShips函数接收字符串输入来创建舰船。输入格式固定为「B-A3-S」,代表战列舰(Battleship)、起始坐标A3、朝向南方(S);多组舰船信息用至少一个空格分隔(例:B-A3-S C-D8-N)。舰船类型对应枚举值:Battleship、Destroyer、Cruiser、Submarine。
我尝试用string::iterator遍历字符串,把当前字符传入Ship::typeFromChar获取ShipType,但始终触发EXCEPTION_WRONG_SHIP_TYPE异常。刚学指针与类,找不到问题根源,相关代码如下:
Player类addShips方法
void Player::addShips(string ships) { string::iterator it; //iterator to go through string //ship attributes ShipType type; Coordinate pos; Orientation o; for (it = ships.begin(); it != ships.end(); it++) { if ((*it == ships.at(0) && isalpha(ships[*it])) || (isalpha(ships[*it]) && isspace(ships[*it-1]))) { type = Ship::typeFromChar(ships[*it]); } else if (ships[*it] == '-') { ...//more conditions for different situations } } }
Ship类typeFromChar方法
ShipType Ship::typeFromChar(char type) { ShipType st; if (type == 'B') { st = BATTLESHIP; } else if (type == 'D') { st = DESTROYER; } else if (type == 'C') { st = CRUISE; } else if (type == 'S') { st = SUBMARINE; } else { throw EXCEPTION_WRONG_SHIP_TYPE; // } return st; }
main函数调用
Player player1("Jack"); try { string ships="B-B3-E S-J10-N C-D7-W D-A1-S"; player1.addShips(ships); } catch (Exception e) { Util::error(ERR_SHIPS); Util::debug(e); return; }
错误根源分析
代码里有两个致命逻辑错误,直接导致传入typeFromChar的字符不是预期的'B'/'C'/'D'/'S':
混淆迭代器的
*it含义:*it是迭代器指向的字符值(比如'B'的ASCII码是66),但你用ships[*it]去访问字符串索引——相当于用字符的ASCII值作为下标,完全超出字符串有效索引范围,拿到的是随机垃圾值,必然触发异常。条件判断逻辑混乱:
第一个if的判断逻辑完全错误:*it == ships.at(0):只有第一个字符会满足,后续舰船类型字符(比如输入里的'S'/'C'/'D')根本不满足isalpha(ships[*it]):同样是用ASCII值当索引,无意义- 正确逻辑应该是:判断当前字符是字母,且要么是字符串第一个字符,要么前一个字符是空格(代表新舰船的开始)
修复后的代码
修正后的Player::addShips方法
void Player::addShips(string ships) { string::iterator it; ShipType type; Coordinate pos; Orientation o; for (it = ships.begin(); it != ships.end(); ++it) { // 判断当前字符是字母,且是新舰船的起始(开头或前一个是空格) if (isalpha(*it) && (it == ships.begin() || isspace(*(it - 1)))) { // 直接传入当前迭代器指向的字符,而非用*it当索引取ships的元素 type = Ship::typeFromChar(*it); } else if (*it == '-') { // 处理后续的坐标和朝向逻辑 ... } } }
额外优化建议
- 遍历迭代器时用
++it替代it++,效率更高(对string迭代器影响不大,但养成好习惯) - 可以用
stringstream分割输入字符串,按空格拆分每个舰船信息串(比如"B-B3-E"),再单独解析子串,比逐个字符遍历更清晰易维护:#include <sstream> #include <string> void Player::addShips(string ships) { std::stringstream ss(ships); std::string shipStr; while (ss >> shipStr) { // 自动按空格分割 // 解析单个shipStr,比如"B-B3-E" char typeChar = shipStr[0]; ShipType type = Ship::typeFromChar(typeChar); // 后续解析坐标和朝向... } }
内容的提问来源于stack exchange,提问作者Lnyka
相关产品推荐
相关产品推荐

