为什么ofstream给我一个回声即。写输入两次

时间:2013-09-21 08:36:09

标签: c++ ofstream

当我运行以下代码时,我编写了例如“Peter”,结果是我在文件中得到“PeterPeter”。

为什么呢?

#include "stdafx.h"
#include "iostream"
#include "iomanip"
#include "cstdlib"
#include "fstream"
#include "string"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    ofstream File2;
    File2.open("File2.dat",ios::out);

    string name;
    cout<<"Name?"<<endl;
    while(!cin.eof())
    {
        cin>>name;
        File2<<name;
    }
    return 0;
}

当我将while循环更改为

while(cin>>name)
{
    File2<<name;
}

它有效。但我不明白为什么第一种方法没有。

我无法回答我自己的问题(因为我没有足够的声誉)。因此,我在这里写下答案:

AHHHH !!!好,谢谢。现在我明白了^^

我一直在测试

    while(!cin.eof())
{
    cin>>name;
    File2<<name;
    cout<<j++<<"cin.eof() "<<cin.eof()<<endl;
}

当我提示 crtl + z 时,他仍然处于while循环中。变量名称保持不变,并且在下一行代码中添加到“File2”

以下是有效的:

while(!cin.eof())
{
    cin>>name;
    if(!cin.eof()){File2<<name;}
    cout<<j++<<"cin.eof() "<<cin.eof()<<endl;
}

2 个答案:

答案 0 :(得分:4)

哼哼,第一百万次被问到这个问题。这是错误的

while(!cin.eof())
{
    cin>>name;
    File2<<name;
}

eof()没有按照您的想法行事。你认为它告诉你你是否在档案的最后,对吧?

eof()实际上做的是告诉你为什么最后一次阅读失败了。因此,在您完成读取以查看失败原因后,您可以调用它,而不是在读取之前执行的操作,以查看它是否会失败。上次读取未失败时eof()的返回值更复杂。这取决于你一直在阅读什么以及你如何阅读它。您尝试在没有失败的情况下使用eof(),因此结果会有所不同。

简短的回答是不要那样,像这样做

while(cin >> name)
{
    File2<<name;
}
顺便说一句,对于轻率的语气感到抱歉,我很想知道为什么你首先写错了代码。我们总是看到这个错误,似乎几乎每个新手都会犯同样的错误,所以我很想知道这个错误来自哪里。你有没有在其他地方看到这些代码,是否有人教你写这个,它对你来说是对的,等等。如果你能在你的情况下解释我会很感激。

答案 1 :(得分:1)

在循环条件中使用std::cin.eof()的基本问题是它在尝试从流中读取任何内容之前测试流状态。此时,流不知道将尝试读取什么,并且它不能通过尝试进行任何预测。基本的见解是:始终必须验证阅读数据读取后是否成功!

第二个问题是eof()仅测试多个错误条件之一。如果没有其他数据,只读std::string只会出错,但对于大多数其他数据类型,也会出现格式故障。例如,阅读int可能会出错,因为格式不匹配。在这种情况下,std::ios_base::failbit将被设置,而fail()会返回trueeof()会一直返回false

测试流本身等同于测试fail(),它检测到流的某些内容有问题(它实际上也会测试流是否为bad())。因此,用于读取文件的规范方法通常具有以下形式之一:

while (input) {
     // multiple read operations go here
     if (input) {
         // processing of the read data goes here
     }
}

while (/* reading everything goes here */) {
    // processing of the read data goes here
}

显然,您可以使用for - 循环而不是while循环。另一种有趣的读取数据的方法是使用std::istream_iterator<T>并假设类型为T的输入运算符。例如:

for (std::istream_iterator<std::string> it(std::cin), end; it != end; ++it) {
    std::cout << "string='" << *it << "'\n";
}

在这些方法中,eof()都没有在主读取循环中使用。但是,在循环之后使用eof()检测循环是否因为文件末尾已到达或因为存在某些格式错误而合理是合理的。