Visual Studio中迷宫搜索代码调试正常,非调试运行异常求助
问题分析:VS调试正常非调试异常的迷宫DFS代码问题
问题现象
编写的迷宫路径搜索代码(实际用栈实现DFS,误称队列)在Visual Studio调试模式下运行正常,但非调试模式下出现异常:无法正确返回结果,有时输出错误值(如重复坐标),多次运行结果不同。在线编译器及他人VS环境中代码正常,手动排查逻辑、重装VS2022均未解决。
代码示例
#include <stack> #include <iostream> #include <string> using namespace std; bool pathExists(string maze[], int nRows, int nCols, int sr, int sc, int er, int ec); // Return true if there is a path from (sr,sc) to (er,ec) // through the maze; return false otherwise class Coord { public: Coord(int r, int c) : m_row(r), m_col(c) {} int r() const { return m_row; } int c() const { return m_col; } private: int m_row; int m_col; }; bool pathExists(string maze[], int nRows, int nCols, int sr, int sc, int er, int ec) { stack<Coord> coordStack; coordStack.push(Coord(sr, sc)); maze[sr][sc] = 'v'; while (!coordStack.empty()) { Coord pos = coordStack.top(); cerr << pos.r() << ' ' << pos.c() << endl; coordStack.pop(); if (pos.r() == er && pos.c() == ec) return true; if (pos.c() + 1 >= 0 && pos.c() + 1 < nCols) { if (maze[pos.r()][pos.c() + 1] == '.') { coordStack.push(Coord(pos.r(), pos.c() + 1)); maze[pos.r()][pos.c() + 1] = 'v'; } } if (pos.r() - 1 >= 0 && pos.r() - 1 < nRows) { if (maze[pos.r() - 1][pos.c()] == '.') { coordStack.push(Coord(pos.r() - 1, pos.c())); maze[pos.r() - 1][pos.c()] = 'v'; } } if (pos.c() - 1 >= 0 && pos.c() - 1 < nCols) { if (maze[pos.r()][pos.c() - 1] == '.') { coordStack.push(Coord(pos.r(), pos.c() - 1)); maze[pos.r()][pos.c() - 1] = 'v'; } } if (pos.r() + 1 >= 0 && pos.r() + 1 < nRows) { if (maze[pos.r() + 1][pos.c()] == '.') { coordStack.push(Coord(pos.r() + 1, pos.c())); maze[pos.r() + 1][pos.c()] = 'v'; } } } return false; } int main() { string maze[10] = { "XXXXXXXXXX", "X..X...X.X", "X.XXXX.X.X", "X.X.X..X.X", "X...X.XX.X", "XXX......X", "X.X.XXXX.X", "X.XXX....X", "X...X..X.X", "XXXXXXXXXX" }; if (pathExists(maze, 10, 10, 5, 3, 8, 8)) cerr << "Solvable!" << endl; else cerr << "Out of luck!" << endl; }
问题根源
核心问题是字符串常量的只读属性导致的未定义行为:
main中maze数组的每个string对象由字符串字面量初始化,这类字面量在C++中属于const char*,通常被编译器放在只读内存段(如.rodata)。- 调试模式下,VS为方便调试,会将字符串放到可写内存区域,因此修改
maze[sr][sc] = 'v'不会触发错误。 - 非调试模式下,编译器优化会将字符串字面量保留在只读内存中,此时修改内存会触发未定义行为——表现为程序崩溃、结果随机、输出异常值等,且不同运行状态下内存布局可能变化,导致多次运行结果不同。
- 在线编译器或他人VS环境中,编译选项或内存布局不同,字符串被放在可写区域,因此代码能正常运行。
解决方案
修改main中maze的初始化方式,确保每个string对象持有可写内存:
- 显式构造可写的
string对象:
string maze[10] = { string("XXXXXXXXXX"), string("X..X...X.X"), string("X.XXXX.X.X"), string("X.X.X..X.X"), string("X...X.XX.X"), string("XXX......X"), string("X.X.XXXX.X"), string("X.XXX....X"), string("X...X..X.X"), string("XXXXXXXXXX") };
- 或者使用
vector<string>初始化,确保每个元素是独立的可写字符串:
vector<string> maze = { "XXXXXXXXXX", "X..X...X.X", "X.XXXX.X.X", "X.X.X..X.X", "X...X.XX.X", "XXX......X", "X.X.XXXX.X", "X.XXX....X", "X...X..X.X", "XXXXXXXXXX" };
修改后,每个string的内部缓冲区可写,maze[r][c]的修改操作合法,非调试模式下也能正常运行。
内容的提问来源于stack exchange,提问作者strawhqt
相关产品推荐
相关产品推荐

