-1

我想在文件中搜索特定单词并返回关于该单词是否存在于文件中的结果。我创建了一个执行此操作的函数。但是在返回程序时崩溃了。这是代码:

bool FindMyWord(const char *fileName)
{
    ifstream myFile (fileName);
    if(!myFile)
        return false;

    string wordSearch = "MyWord";
    string endSearch = "LastWord";
    bool result;
    while(1)
    {
        char read[20];
        myFile.getline(read, 1000, '\n');
        string line(read, read+20);
        if(line.find(wordSearch) != string::npos)
        {
            result = true;
            break; //comes here after looping about 10 times
        }
        if(line.find(endSearch) != string::npos)
        {
            result = false;
            break;
        }
    }
    myFile.close();
    return result;
} // <- crash when F10 is pressed after this

在VS2010中调试时我发现return result;在函数的倒数第二行执行“”后发生崩溃,即当黄色光标用于函数的最后一个右括号时。我收到一条消息

A buffer overrun has occurred in myApp.exe which has corrupted the program's internal
state. Press Break to debug the program or Continue to terminate the program.

这是什么错误?我这样调用函数:

bool result = FindMyWord("myFileName.stp");

更新:每一行都有不同的字符,它们> 20。我想阅读第一个 20 个字符,如果这些字符中不存在这个词,那么我想跳到下一行。最初我使用myFile.getline(read, 20, '\n');但在第一个循环之后,每个后续循环都会导致 NULL 被传递给读取。所以我让它读取 1000 因为在读取 1000 个字符之前它会找到 '\n' 并转到下一行。实现相同目标的更好机制将非常有帮助。

4

4 回答 4

4

为什么不使用 astd::string而不是固定长度的缓冲区?

bool FindMyWord(const char *fileName)
{
    std::ifstream myFile (fileName);
    if(!myFile) {
        return false;
    }

    std::string wordSearch = "MyWord";
    std::string endSearch = "LastWord";
    bool result;
    std::string line;
    while(std::getline(myFile, line))
    {
        if(line.find(wordSearch) != std::string::npos)
        {
            result = true;
            break; //comes here after looping about 10 times
        }
        if(line.find(endSearch) != std::string::npos)
        {
            result = false;
            break;
        }
    }
    myFile.close();
    return result;
} 

缓冲区溢出导致了太多的安全问题。只是不要使用固定长度的缓冲区!

这也稍微正确一些,因为它会检查流中的错误。

PS我讨厌using namespace std

于 2013-03-11T12:13:24.200 回答
3

myFile.getline(read, 1000, '\n');将从 address 开始最多读取 1000 个字节到内存中readread是一个 20 字节的堆栈缓冲区,因此您可能会写超出分配内存的末尾。这样做的影响是不确定的,但很可能会崩溃。

要解决此问题,您应该将read缓冲区的大小传递给getline;

myFile.getline(read, sizeof(read), '\n');

(请注意,sizeof(read)这只适用于堆栈缓冲区。如果read在堆上分配,sizeof只会告诉您指针的大小而不是它指向的分配内存。)

于 2013-03-11T12:07:35.910 回答
0

在您可以使代码正常工作之前,请忘记char[]. (正如其他人指出的那样,您有一个缓冲区溢出。将任何 C 样式数组作为局部变量很容易做到。)由于您正在寻找单词,初始代码可以简单如下:

std::string word;
while ( myFile >> word && word != "MyWord" && word != "LastWord" ) {
}
return word == "MyWord";

这当然可以更快,但如果"LastWord"不是很远进入文件,它可能没有必要。(顺便说一句:通常没有必要关闭输入中使用的文件。析构函数会处理这个问题,并且由于您已经在每次输入后检查了状态,因此无需担心更多错误检查。)

于 2013-03-11T12:16:32.593 回答
0

在上面的代码中,我能想到的一个导致缓冲区溢出的地方是:

myFile.getline(读取, 1000, '\n');

由于“读取”是一个可容纳 20 个字符的缓冲区,因此如果文件的行大于该行,它就无法容纳。

另外,请做eof检查。我会建议这样的事情:


bool FindMyWord(const char *fileName)
{
    if(!myFile)
        return false;

ifstream myFile (fileName);

const char* wordSearch = "MyWord";
const char* endSearch  = "LastWord";
bool result = false;
string line;

while(std::getline(myFile, line))
{
    if(line.find(wordSearch, 0, 20) != string::npos)
    {
        result = true;
        break; //comes here after looping about 10 times
    }

    if(line.find(endSearch, 0, 20) != string::npos)
    {
        result = false;
        break;
    }
}

myFile.close();
return result;

}

于 2013-03-11T12:51:00.240 回答