首页 > 解决方案 > C++ 中 fstream 的行为

问题描述

我制作了以下脚本,应该从文件中读取:

    char match[] = "match";

    int a;
    int b;

    inp >> lin;
    while(!inp.eof()) {
        if(!strcmp(lin, match)) {
            inp >> a >> b;
            cout << a << " " << b <<endl;
        }
        inp >> lin;
    }

    inp.close();
    return num_atm;
}

它应该读取所​​有单词,如果一行以 match 开头,它还应该打印该行的其余部分。

我的输入文件是这样的:

match 1 2 //1
match 5 2 //2
nope 3 6 //3
match 5 //4
match 1 4 //5
match 5 9 //6

它将正确打印 1 2、5 2 并跳过 3 6。但是,它会卡住并继续打印 5 0 并永远继续打印 5 0。我得到匹配被放入 b,这是一个整数,但我不明白为什么这是循环的。输入读取不应该匹配 4 一次,尝试读取/写入 5 并匹配,然后使用第 4 行和第 5 行的匹配完成?然后它应该接下来读取数字 1 和 4,然后从数字 6 开始匹配。

我也明白,由于这个词不适合整数,它会在第五行再次读取 match,但这不是它的作用。

它回到它已经读取的第四行中的匹配,并再次读取它。为什么是这样?

标签: c++fstream

解决方案


当您阅读时,>>行尾的处理方式与空格相同:它们只是更多被跳过的空格。这意味着你看到

match 1 2 
match 5 2 
nope 3 6 
match 5 
match 1 4 
match 5 9 

但程序看到

match 1 2 match 5 2 nope 3 6 match 5 match 1 4 match 5 9 

让我们快进到事情向南的地方

流的内容:

nope 3 6 match 5 match 1 4 match 5 9 

加工

inp >> lin; // reads nope stream: 3 6 match 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // nope != match skip body
}
inp >> lin; // reads 3 stream: 6 match 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // 3 != match skip body
}
inp >> lin; // reads 6 stream: match 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // 6 != match skip body
}
inp >> lin; // reads match stream: 5 match 1 4 match 5 9 
if(!strcmp(lin, match)) { // match != match Enter body
    inp >> a >> b; // reads 5 and fails to parse match into an integer.
                   // stream: match 1 4 match 5 9 
                   // stream now in failure state
    cout << a << " " << b <<endl; // prints 5 and garbage because b was not read

}
inp >> lin; // reads nothing. Stream failed
if(!strcmp(lin, match)) { // match != match Enter body
    inp >> a >> b; // reads nothing. Stream failed
                   // stream: match 1 4 match 5 9 
                   // stream now in failure state
    cout << a << " " << b <<endl; // prints g and garbage because b was not read

}

因为没有任何东西被读过,while(!inp.eof())是完全没有价值的。永远无法到达文件的末尾。该程序将永远循环,可能会打印它上次读取的任何内容。成功读取。

如果您有一条没有 2 个数字的匹配线,则解决此问题完全取决于您想要做什么,但典型的框架看起来像

std::string line;
while(std::getline(inp, line) // get a whole line. Exit if line can't be read for any reason.
{
    std::istringstream strm(line);
    std::string lin;
    if(strm >> lin && lin == match) // enters if lin was read and lin ==  match
                                    // if lin can't be read, it doesn't matter. 
                                    // strm is disposable
    {
        int a;
        int b;

        if (strm >> a >> b) // enters if both a and b were read
        {
            cout << a << " " << b <<"\n"; // endl flushes. Very expensive. just use a newline.
        }
    }
}

输出应该是这样的

1 2 
5 2 
1 4 
5 9 

如果您想使用匹配 5b ...如果文件中没有,则取决于您要b输入的内容。


推荐阅读