You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++递归遍历目录触发xmemory访问违例错误求助

递归遍历目录查找文件时触发访问违例异常的问题

我写了一段C代码用于递归遍历目录查找指定文件,运行时触发如下错误:
Exception thrown at 0x00007FF6CA077375 in console test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
错误来自"xmemory"文件,需要先解决这个异常。开发环境:Visual Studio 17.3.0,C
20标准(/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 ==========

问题分析与修复方案

核心问题点

  1. 字符串越界访问:endstr函数中,int i = str.length();后直接访问str[i],但字符串索引范围是0到str.length()-1,str[i]属于越界访问,直接触发未定义行为,是访问违例的直接原因之一。
  2. 函数未保证返回值:getFile声明返回string,但多个代码分支没有返回值(比如遍历完目录、递归后未找到文件),导致函数结束时返回垃圾值,触发内存访问错误。
  3. 递归逻辑完全颠倒:当前代码判断「如果目录已在explored中才递归」,正确逻辑应该是「目录不在explored中才递归」,否则根本不会进入子目录查找。
  4. 文件名匹配逻辑错误:用完整路径fl和文件名endstr(item, "\\")比较,永远不会相等,应该提取文件的文件名部分进行匹配。
  5. 非目录文件处理错误:遇到非目录文件直接break,导致当前目录下后续文件都不遍历,丢失查找机会。
  6. 全局变量滥用: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 00:54:13