2017-10-15 114 views
2

我目前遇到导航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循环。我有三倍检查我的数组的大小,以确保没有问题,我试图读入一个不存在的行。

+2

答案与“为什么是水湿”和“为什么是天蓝色”是一样的答案。 getline()'的全部目的是从输入流中读取下一行,并将其保存在不包含换行符*的'std :: string' *中。您将永远不会在由'std :: getline()',***定义的***填充的字符串中获得'\ n'。这就是'std :: getline()'的作用。 –

+0

也许你感到困惑,因为你习惯于在C中使用'fgets()',它保持字符串中的换行符。但是C++'getline()'不会那样做。 – Barmar

+0

18446744073709551615是2到64次方减1.这是最大的无符号64位整数。一个常见的方法是将-1馈入一个期望无符号64位整数的变量。在某些地方,你试图从“名称”的元素之一开始看,可能性很大。 – user4581301

回答

1

总是检查find函数的返回值。例如:

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

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

正如在评论中指出,names[r]不包含\n在这种情况下。 p始终为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;

0

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

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

以了解你的文件的确切格式的优势。该文件已经以完美和简单的方式被操纵。另外,如果你不知道你的数据的大小。我鼓励你通过一个固定大小的数组使用向量。