【问题标题】:Program can't find carriage return or newline. Returns out of range程序找不到回车或换行。返回超出范围
【发布时间】:2018-03-26 20:17:21
【问题描述】:

我目前在导航 txt 文件时遇到问题,因此我可以将其读入数组。该程序编译得很好,但是当我运行它时它会在终端中返回:

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::erase: __pos (which is 18446744073709551615) > this->size() (which is 14)
Aborted (core dumped)

代码如下:

#include<cstdlib>
#include<cmath>
#include<fstream>
#include<sstream>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<cassert>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<locale.h>
#include<stdio.h>
#include<functional>
#include<math.h>

using namespace std;

int main(int argc, char**argv)
{
    int r=0;
    int p=0;
    int c=0;
    string names[20];
    double scores[20][10];

    ifstream infile;
    infile.open("./bowlers.txt");

    for(int r=1;r<=10;r++)
    {
        getline(infile,names[r]);

        p=names[r].find_first_of("\n") ;
        names[r].erase(p,2);

        for(c=1;c<=5;c++)
        {
        infile>>scores[r][c];
        }
        infile.ignore(100,'\n');
    }
    infile.close();

    for(int r=1;r<=10;r++)
    {
        cout<<fixed<<setprecision(2)<<endl;
        cout<<names[r]<<endl;

    }  

    return 0;
}

我正在使用的 txt 文件如下所示:

charles
123
321
222
rose
432
515
123
Greg
123
553
136

所以这是我自己研究这个问题时发现的:

  1. Unix 和 Windows 对 EOL 的处理方式不同。
  2. 我的部分问题是:

        p=names[r].find_first_of('\n') ;
        names[r].erase(p,2);
    

    导致问题,因为从未找到\n 它返回-1,而您不能.erase -1?

我尝试过使用\r,\n\r\n 等所有可以想到的方法,但我总是收到大致相同的输出。我也尝试过更改 .txt 文件的编码。唯一的区别在于(which is 14)。这个数字会根据我对 .txt 文件的编码方式而波动。我还在 vim 和 :set list 中打开了 .txt 文件以查看换行符。所以我知道他们在那里。

这只是一个更大的学校项目的部分代码,我对 c++ 还不是很有经验。谁能指出我正确的方向?我觉得一旦我弄清楚了我的这部分代码,我应该能够完成这个项目。

注意:txt 文件只是一个示例,因此不要过多考虑我的数组大小或 for 循环中的参数。我三次检查了数组的大小,以确保我尝试读取不存在的行时没有问题。

【问题讨论】:

  • 这里的答案和“水为什么湿”和“天为什么是蓝色的”是一样的答案。 getline() 的全部目的是从输入流中读取下一行,并将其保存在 std::string 不包括换行符中。你永远不会在std::getline() 填充的字符串中得到\n按定义。这就是std::getline() 的工作原理。
  • 也许你很困惑,因为你习惯了 C 语言中的fgets(),它将换行符保留在字符串中。但是 C++ getline() 没有这样做。
  • 18446744073709551615 是 2 的 64 次方减去 1。这是最大的无符号 64 位整数。一种常见的方法是将 -1 输入到期望无符号 64 位整数的变量中。很有可能您尝试在某个地方查看names 的元素之一的开头。
  • 也许我还应该补充一点,我的导师在一个类似的例子中使用了\r,并让它在 Windows 机器上使用 Netbeans 非常适合他。不确定这是否进一步澄清。
  • 所以@SamVarshavchik 如果getline() 没有得到\n。我将如何操纵以下几行来忽略分数并为scores 数组获取它们?我不是在找人为我做功课,但我相信我需要朝着正确的方向轻推,因为我认为我需要完全改变我的代码。对吗?

标签: c++ vim newline carriage-return


【解决方案1】:

始终检查查找函数的返回值。示例:

size_t p = names[r].find_first_of("\n");
if (p != string::npos)
    names[r].erase(p, 2);

如果没有找到\n,则返回值为string::npos(可能是0xFFFFFFFF0xFFFFFFFFFFFFFFFF),这是无效索引。尝试访问该索引会导致错误。

如 cmets 中所述,names[r] 在这种情况下不包含 \np 始终为 string::npos,不需要此操作。

for(c=1;c<=5;c++)
{
infile>>scores[r][c];
}

每个名字下面只有 3 个整数,所以你应该数到 3,而不是 5。这段代码应该可以工作:

for(int r = 1; r <= 10; r++)
{
    getline(infile, names[r]);
    for(int c = 1; c <= 3; c++)
        infile >> scores[r][c];
    infile.ignore(100, '\n');
}

或者你可以添加更多的错误检查,例如if (!(infile &gt;&gt; scores[r][c])) break;

【讨论】:

    【解决方案2】:

    我不知道您为什么需要检测换行符。如果您正在寻找提取姓名和号码,您可以执行以下操作

    string word;
    int i(0); 
    while ( infile >> word ){
        if(!(i%4)){
            //name 
            std::cout << word << endl;
        }else{
            //number
        }
        ++i;
    }
    

    充分了解文件的确切格式。该文件已经是一种完美且易于操作的方式。此外,如果您不知道数据的大小。我鼓励您在固定大小的数组上使用向量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-20
      • 2014-10-15
      • 1970-01-01
      • 2018-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-11
      相关资源
      最近更新 更多