【问题标题】:getline seems to not working correctlygetline 似乎无法正常工作
【发布时间】:2011-09-11 02:29:01
【问题描述】:

请告诉我我在这里做错了什么。我想做的是:
1.有四个数字的txt文件,每个数字有15位:

std::ifstream file("numbers.txt",std::ios::binary);

我正在尝试将这些数字读入我的数组:

  char num[4][15];

我想我正在做的是:只要你没有到达文件末尾,就将每一行(最多 15 个字符,以 '\n' 结尾)写入 num[lines]。但这有点行不通。首先它只正确读取第一个数字,其余只是“”(空字符串),其次 file.eof() 似乎也不能正常工作。在我在此代码下方显示的 txt 文件中,我达到了等于 156 的行数。这是怎么回事?

                for (unsigned lines = 0; !file.eof(); ++lines)
                {
                    file.getline(num[lines],15,'\n');  
                }

所以整个“例程”看起来是这样的:

int main()
{
std::ifstream file("numbers.txt",std::ios::binary);

char numbers[4][15];

            for (unsigned lines = 0; !file.eof(); ++lines)
            {
                file.getline(numbers[lines],15,'\n');// sizeof(numbers[0])
            }
}

这是我的 txt 文件的内容:

111111111111111
222222222222222
333333333333333
444444444444444

附言
我正在使用 VS2010 sp1

【问题讨论】:

  • 你是认真的吗? getline 工作不正常?难以置信!
  • @Vlad 我只是不确定,可能是我在做某事,但我不知道在哪里。

标签: c++ fstream getline


【解决方案1】:

不要使用 eof() 函数!读取行的规范方法是:

while( getline( cin, line ) ) {
    // do something with line
}

【讨论】:

  • @Neil,不使用 eof 有什么特别的原因吗?
  • @Bruce:在对您显然不太了解的语言的问题的答案投反对票之前,谷歌搜索“安全布尔成语”怎么样? +1 作为补偿,这是答案。
  • @Neil 和您展示的方式在某种程度上不适用于我的多维数组,我收到错误“没有重载函数的实例与参数列表匹配”
  • @smallB 使用 eof() 通常是试图猜测下一个 I/O 会做什么,而实际上它会告诉你上一个 I/O 做了什么。至于它不能与您的代码一起使用,那么有很多原因可能不是这种情况。当您正在阅读 char[] 的(再次为什么???)时,您想要 while(file.getline(...))。
  • @Neil 它不起作用,因为正如我所说,我从 IntelliSense 收到一个错误,告诉我这个函数不能接受这些参数。
【解决方案2】:

将其更改为以下内容:

#include <cstring>

int main()
{
    //no need to use std::ios_base::binary since it's ASCII data
    std::ifstream file("numbers.txt");

    //allocate one more position in array for the NULL terminator
    char numbers[4][16];

    //you only have 4 lines, so don't use EOF since that will cause an extra read
    //which will then cause and extra loop, causing undefined behavior
    for (unsigned lines = 0; lines < 4; ++lines)
    {
        //copy into your buffer that also includes space for a terminating null
        //placing in if-statement checks for the failbit of ifstream
        if (!file.getline(numbers[lines], 16,'\n'))
        {
            //make sure to place a terminating NULL in empty string
            //since the read failed
            numbers[lines][0] = '\0';
        }
    }

}

【讨论】:

  • 从 getline doc 应该自动添加终止的空值,然后你做了两次相同的工作,首先你从文件复制到临时文件,然后你从临时文件复制到数字。一定有更好的办法!
  • -1:哇,你非常相信getline 不会出错。
  • 好的,我在getline 调用中添加了更多安全功能
  • @smallB:我已经缩减了代码,但是您肯定会想要添加一个安全功能,以在getline 失败时终止您的字符串。
【解决方案3】:

file.getline()提取14个字符,填入num[0][0] .. num[0][13]。然后它将'\0' 存储在num[0][14] 中,并在file 上设置failbit,因为这是在缓冲区已满但未到达终止字符时所做的。

进一步尝试调用 file.getline() 什么都不做,因为故障位已设置。

!file.eof() 的测试返回 true,因为未设置 eofbit。

编辑:举个例子,最好是使用字符串,当然,但要填写你的 char 数组,你可以这样做:

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream file("numbers.txt"); // not binary!
    char numbers[4][16]={}; // 16 to fit 15 chars and the '\0'
    for (unsigned lines = 0;
         lines < 4 && file.getline(numbers[lines], 16);
         ++lines)
    {
        std::cout << "numbers[" << lines << "] = " << numbers[lines] << '\n';
    }
}

在 Visual Studio 2010 SP1 上测试

【讨论】:

  • 没有任何迹象表明它会遇到任何类型的故障,那么为什么要设置failbit
  • @rcollyer 在这种情况下的失败是未能执行请求的操作(“读取一行”)
  • 我应该再往下读一点。让我更欣赏std::string 版本的getline
【解决方案4】:

看起来第一个 like 末尾的 '\n' 没有被考虑,而是保留在缓冲区中。所以在接下来的getline() 它会被读取。

尝试在每个 getline() 之后添加一个 file.get()。

如果一个 file.get() 不起作用,请尝试两个,因为在 Windows 默认文件编码下,该行以'\n\r\'(或'\r\n',我永远不知道:)

【讨论】:

    【解决方案5】:

    根据ifstream doc,在读取 n-1 个字符或找到分隔符后停止读取:第一次读取只需要 14 个字节。

    它读取字节:'1'(字符)是 0x41:你的缓冲区将填充 0x41 而不是 1,正如你所期望的,最后一个字符将是 0(c 字符串的结尾)

    旁注,您的代码不会检查行是否超出您的数组。

    使用 getline 假设您期待文本并且以二进制模式打开文件:对我来说似乎是错误的。

    【讨论】:

      猜你喜欢
      • 2017-09-04
      • 2012-05-06
      • 2013-02-17
      • 2017-10-09
      • 2017-08-03
      • 2014-05-02
      • 2016-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多