5

我在 C++ 中尝试了一些文件读取策略,我遇到了这个。

ifstream ifsw1("c:\\trys\\str3.txt");
char ifsw1w[3];
do {
    ifsw1 >> ifsw1w;
    if (ifsw1.eof())
        break;
    cout << ifsw1w << flush << endl;
} while (1);
ifsw1.close();

该文件的内容是

第一第一第一第二
第二第一第二第二

当我看到输出时,它打印为

第一第一
第一秒
第二优先

我希望输出类似于:

冷杉
stf
税务局
tfi
......

此外,我看到“secondsecond”没有被打印出来。我猜最后一次读取已经遇到了 eof 并且 cout 可能没有被执行。但第一种行为是不可理解的。

4

5 回答 5

7

提取运算符没有 ifsw1w 变量大小的概念,并且(默认情况下)将提取字符,直到它遇到空格、null 或 eof。这些很可能存储在 ifsw1w 变量之后的内存位置中,如果您定义了其他变量,则会导致错误的错误。

要获得所需的行为,您应该能够使用

ifsw1.width(3);

限制要提取的字符数。

于 2011-02-13T00:24:03.343 回答
2

您正在破坏内存...它的读数超过了您定义的 3 个字符(它的读数直到遇到空格或换行...)。

逐字符读取以实现您提到的输出。

编辑: Irritate 是对的,这也有效(有一些修复并没有得到确切的结果,但这就是精神):

char ifsw1w[4];
    do{
        ifsw1.width(4);
        ifsw1 >> ifsw1w;
        if(ifsw1.eof()) break;
        cout << ifsw1w << flush << endl;
    }while(1);
    ifsw1.close();
于 2011-02-13T00:24:56.280 回答
2
  1. 安全使用几乎是不可能的std::istream& operator>>(std::istream&, char *)——就像gets在这方面一样——你无法指定缓冲区大小。流只是写入您的缓冲区,结束。(您上面的示例调用未定义的行为)。要么使用接受 a 的重载std::string,要么使用std::getline(std::istream&, std::string).

  2. 检查eof()不正确。你想要fail()。你真的不关心流是否在文件的末尾,你只关心你没有提取信息。

对于这样的事情,您最好将整个文件读入字符串并从那时起使用字符串操作。您可以使用字符串流来做到这一点:

#include <string> //For string
#include <sstream> //For stringstream
#include <iostream> //As before

std::ifstream myFile(...);
std::stringstream ss;
ss << myFile.rdbuf(); //Read the file into the stringstream.
std::string fileContents = ss.str(); //Now you have a string, no loops!
于 2011-02-13T00:25:29.847 回答
2

代码具有未定义的行为。当你做这样的事情时:

char ifsw1w[3];

ifsw1 >> ifsw1w;

operator>>接收指向缓冲区的指针,但不知道缓冲区的实际大小。因此,它无法知道它应该在两个字符后停止读取(并注意它应该是 2,而不是 3——它需要空间'\0'来终止字符串)。

底线:在您探索读取数据的方法时,最好忽略此代码。你可以从这样的代码中学到的所有东西都是你应该避免的。然而,通常只遵循一些经验法则比尝试研究所有可能出现的问题更容易。

  1. 用于std::string读取字符串。
  2. 仅对固定大小的数据使用固定大小的缓冲区。
  3. 当您确实使用固定缓冲区时,请传递它们的大小以限制读取的数量。
  4. 当你想读取一个文件中的所有数据时,std::copy可以避免很多错误:

    std::vector<std::string> strings;   
    std::copy(std::istream_iterator<std::string>(myFile),
              std::istream_iterator<std::string>(),
              std::back_inserter(strings));
    
于 2011-02-13T00:35:47.070 回答
1

要读取空格,您可以使用“noskipws”,它不会跳过空格。

ifsw1 >> noskipws >> ifsw1w;

但是如果你只想获取 3 个字符,我建议你使用 get 方法:

ifsw1.get(ifsw1w,3);
于 2011-02-13T00:22:15.460 回答