C++递归遍历目录触发xmemory访问违例错误求助
递归遍历目录查找文件时触发访问违例异常的问题
我写了一段C代码用于递归遍历目录查找指定文件,运行时触发如下错误:Exception thrown at 0x00007FF6CA077375 in console test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
错误来自"xmemory"文件,需要先解决这个异常。开发环境:Visual Studio 17.3.0,C20标准(/std:c++20),编译器MinGW gcc。
代码
#include <string> #include <vector> #include <iostream> #include <filesystem> #include <algorithm> // 原代码漏写该头文件,find函数依赖它 using std::filesystem::directory_iterator; namespace fs = std::filesystem; using namespace std; string endstr(string str, string delim) { int i = str.length(); while (str[i] != delim[0]) { if (i == 0) break; i--; } return str.substr(i + 1, str.length()); } string start = "C:\\"; vector<string> explored; string fl; string *dir; string getFile(const char* item, string startPath) { for (const auto& file : directory_iterator(startPath)) { fl = file.path().string(); cout << fl << endl; if (fl == endstr(item, "\\")) { return fl; } else if (file.is_directory()) { if (find(explored.begin(), explored.end(), fl) != explored.end()) { getFile(item, fl); } } else { break; } } explored.push_back(fl); } int main() { getFile("Terraria.exe", "C:\\"); }
调试日志
'console test.exe' (Win32): Loaded 'C:\Users\willk\source\repos\console test\x64\Debug\console test.exe'. Symbols loaded. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\ntdll.dll'. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\kernel32.dll'. 'console test.exe' (Win32): Loaded 'C:\Program Files\Avast Software\Avast\aswhook.dll'. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\KernelBase.dll'. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\msvcp140d.dll'. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\vcruntime140d.dll'. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\vcruntime140_1d.dll'. 'console test.exe' (Win32): Loaded 'C:\Windows\System32\ucrtbased.dll'. The thread 0x5cec has exited with code 0 (0x0). Exception thrown at 0x00007FF703A47415 in console test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
构建日志
Build started... 1>------ Build started: Project: console test, Configuration: Debug x64 ------ 1>console test.cpp 1>C:\Users\willk\source\repos\console test\console test\console test.cpp(14,25): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data 1>C:\Users\willk\source\repos\console test\console test\console test.cpp(45): warning C4715: 'getFile': not all control paths return a value 1>console test.vcxproj -> C:\Users\willk\source\repos\console test\x64\Debug\console test.exe 1>Done building project "console test.vcxproj". ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
问题分析与修复方案
核心问题点
- 字符串越界访问:
endstr函数中,int i = str.length();后直接访问str[i],但字符串索引范围是0到str.length()-1,str[i]属于越界访问,直接触发未定义行为,是访问违例的直接原因之一。 - 函数未保证返回值:
getFile声明返回string,但多个代码分支没有返回值(比如遍历完目录、递归后未找到文件),导致函数结束时返回垃圾值,触发内存访问错误。 - 递归逻辑完全颠倒:当前代码判断「如果目录已在
explored中才递归」,正确逻辑应该是「目录不在explored中才递归」,否则根本不会进入子目录查找。 - 文件名匹配逻辑错误:用完整路径
fl和文件名endstr(item, "\\")比较,永远不会相等,应该提取文件的文件名部分进行匹配。 - 非目录文件处理错误:遇到非目录文件直接
break,导致当前目录下后续文件都不遍历,丢失查找机会。 - 全局变量滥用:
fl、explored等全局变量容易导致状态混乱,尤其是递归调用时会被多次覆盖。
修正后的代码
#include <string> #include <vector> #include <iostream> #include <filesystem> #include <algorithm> namespace fs = std::filesystem; using namespace std; vector<string> explored; string getFile(const string& targetFileName, const string& startPath) { try { for (const auto& entry : fs::directory_iterator(startPath)) { const auto& path = entry.path(); string fullPath = path.string(); cout << fullPath << endl; // 匹配目标文件名 if (entry.is_regular_file() && path.filename().string() == targetFileName) { return fullPath; } // 处理目录:未遍历过则递归 if (entry.is_directory()) { if (find(explored.begin(), explored.end(), fullPath) == explored.end()) { explored.push_back(fullPath); // 先标记为已遍历,避免重复进入 string result = getFile(targetFileName, fullPath); // 递归找到文件后立即向上返回结果 if (!result.empty()) { return result; } } } // 非目录文件不做处理,继续遍历下一个 } } catch (const fs::filesystem_error& e) { // 处理权限不足等文件系统错误,避免程序崩溃 cerr << "文件系统错误: " << e.what() << endl; } // 未找到返回空字符串 return ""; } int main() { string result = getFile("Terraria.exe", "C:\\"); if (!result.empty()) { cout << "找到文件: " << result << endl; } else { cout << "未找到目标文件" << endl; } return 0; }
关键修改说明
- 移除了容易出错的
endstr函数,直接使用fs::path::filename()提取文件名,更可靠且符合C++标准库用法。 - 修复递归逻辑:先判断目录未被遍历过,再标记为已遍历并递归,避免重复进入同一目录。
- 保证
getFile函数所有路径都返回值:找到文件返回路径,未找到返回空字符串。 - 处理递归返回值:递归调用后如果找到文件,立即向上返回结果,避免无效遍历。
- 添加文件系统异常捕获:处理权限不足、目录不存在等错误,防止程序崩溃。
- 移除错误的
break语句,确保遍历当前目录下所有文件和子目录。 - 消除
size_t转int的警告(原代码的C4267警告已解决)。
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

