当我们尝试提取文件中的行时,实际会发生什么,之后 'eof' 字符与 istream::getline() 和 std::getline() 一起出现

What's actually happens when we try to extract line in file after which `eof` character is present with istream::getline() and std::getline()

提问人:Abhishek Mane 提问时间:10/24/2021 最后编辑:PreethiSamanthaBennetAbhishek Mane 更新时间:11/4/2021 访问量:754

问:

roha.txt

I really love to spend time with you.
Let's go for coffee someday.
Enjoy whole day and cherish the memories.

代码-1

#include <iostream>
#include <fstream>


int main()
{
    char str[100];

    std::ifstream fin;
    fin.open("roha.txt", std::ios::in);

   for(int i=0; i<=3; i++)
   {
        std::cout<<bool(fin.getline(str,100) )<<" "<<str<<fin.fail()<<"\n";
   }

}

输出

1 I really love to spend time with you.0
1 Let's go for coffee someday.0
1 Enjoy whole day and cherish the memories.0
0 1

代码-2

#include <iostream>
#include <fstream>
#include <string>
using std::string;

int main()
{
   string str;

    std::ifstream fin;
    fin.open("roha.txt", std::ios::in);

    for(int i=0; i<=3; i++)
    {
        std::cout<<bool(std::getline(fin,str) )<<" "<<str<<fin.fail()<<"\n";
    }

}

输出

1 I really love to spend time with you.0
1 Let's go for coffee someday.0
1 Enjoy whole day and cherish the memories.0
0 Enjoy whole day and cherish the memories.1

我知道 和 是不同的。但我想知道到底发生了什么。C-style char arrayistream::getlinestringstd::getline

我猜对于 ,它提取了第 1 次、第 2 次的字符串,当它尝试提取它看到的第 3 次时,它会在 .stringstd::getlineeofeof

下次我们尝试提取它时,只是遇到,所以它没有提取任何东西并设置.eoffail-bit

string str没有被修改,所以当我们尝试打印它时,只有最后提取的字符串才会被打印出来。

我不知道我的想法是否正确......

我也不能对 .istream::getline()C-style char array

C++ 字符串 文件处理 eof getline

评论

2赞 Richard Critten 10/24/2021
“......a) 输入的文件结束条件,在这种情况下,getline 设置 eofbit....“ 完整信息在这里 - en.cppreference.com/w/cpp/string/basic_string/getline
1赞 Pete Becker 10/24/2021
这并不能解决问题,但要养成使用有意义的值初始化对象的习惯,而不是默认初始化它们并立即覆盖默认值。在这种情况下,这意味着更改为 .此外,对于 ,“i” 代表 “输入”。你不需要重复; 就足够了。std::ifstream fin; fin.open("roha.txt", std::ios::in);std::ifstream fin("roha.txt", std::ios::in);ifstreamstd::ifstream("roha.txt");
0赞 Pete Becker 10/24/2021
请注意,对调用 和 的顺序没有要求。编译器可以自由地首先调用并存储结果,然后调用并存储该结果,然后进行插入。在问题的代码中,这意味着程序可以在调用 之前调用。(这可能在最近的标准中发生了变化;我最近没有注意细节。然而,像那个具有隐式顺序依赖关系的输出语句这样的语句很难阅读并且容易出错)std::cout << f() << g();f()g()g()f()fin.fail()fin.getline(str, 100)
0赞 Abhishek Mane 10/24/2021
@PeteBecker首先感谢。注意到第一条评论,我将来会处理这个问题。现在关于第二条评论,我故意放在前面,这样我就可以检查是否失败?fin.fail()fin.getline(str, 100)getline()
1赞 Pete Becker 10/24/2021
只需在 output 语句之前调用即可。流的状态是持久的;如果调用失败,会告诉你。在大多数情况下,你会使用类似的东西来管理一系列输入。但这不是此代码正在执行的操作,并且无需直接测试调用的返回值。fin.getline(str, 100);getlinebool(fin)while (fin.getline(str, 100))getline

答:

3赞 Homer512 11/1/2021 #1

引用该标准,第 21.3.3.4 节插入器和提取器 [string.io]:

条款 6:

[...]构造对象后,如果 转换为 ,则调用并提取字符并将其附加到 [...] 中,直到发生以下任一情况:sentrysentrytruestr.erase()isstr

  • 文件末尾发生在输入序列上(在这种情况下,函数调用 .getlineis.setstate(ios_base::eofbit))
  • [...]

第 29.7.4.1.3 节 类:basic_istream::sentry

explicit sentry(basic_istream<charT, traits>& is, bool noskipws = false);效果:如果是,则调用 [...] 如果,在完成任何准备工作后,是 ,否则,.在准备过程中,构造函数可以调用 [...]is.good()falseis.setstate(failbit)is.good()trueok_ != falseok_ == falsesetstate(failbit)

explicit operator bool() const;返回:ok_

那么,字符串版本发生了什么:

  1. 提取最后一个字符串。这将设置 eofbit,但不设置 failbit
  2. 你又得到线了
  3. getline 构造哨兵
  4. 哨兵检查.这是假的,因为设置了 eofbitis.good()
  5. 哨兵设置故障位并将其成员ok_设置为 false
  6. getline 函数检查哨兵是否为 true(运算符布尔)。这是错误的
  7. getline 函数在清除旧字符串之前返回

部分 29.7.4.3 未格式化的输入函数

第 21 条(这是关于 C 字符串版本):

在任何情况下,如果大于零,则它将 null 字符 (using ) 存储到数组的下一个连续位置ncharT()

其余的措辞类似于字符串版本。换句话说,getline 的 C 字符串版本始终存储一个字符,即使它失败了。该版本没有,大概是因为如果您忘记检查故障位,它不会引入与 C 版本相同的内存安全问题。'\0'std::string

评论

0赞 Abhishek Mane 11/2/2021
你的答案我不清楚。你是说这是错误吗?还是别的什么?请详细回答。
0赞 Homer512 11/2/2021
@AbhishekMane 是的,对我来说,这看起来像是您正在使用的标准库实现中的一个错误。如果我正确阅读了标准,您为 istream::getline(char*, size_t) 描述的行为应该与 getline(istream, string) 完全相同。如果两个版本都能够从流中提取至少一个字符,则它们都不应设置 failbit。
1赞 Abhishek Mane 11/2/2021
看到 ARE 设置的两个重载,当它们遇到并且无法检索字符时,这按预期工作没有问题。我的观点是,当我再次尝试打印 ( ) 时,它会打印上次提取时存储的内容,但是当您使用 ( ) 时,它打印没有任何表示空字符串,所以这里发生了什么我没有得到?getline()failbiteofstring strgetline(istream, string)char str[100]cin.getline(str,n)
0赞 Homer512 11/2/2021
@AbhishekMane你是对的,我误解了你的问题。我已经重写了答案