程序找不到回车 return 或换行符。 Returns 超出范围

Program can't find carriage return or newline. Returns out of range

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

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 从未找到它 returns -1,而你不能 .erase -1?

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

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

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

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

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

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

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

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

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

如评论中所述,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 >> scores[r][c])) break;