Search code examples
c++vimnewlinecarriage-return

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


I'm currently having an issue navigating a txt file so I can read it into an array. The program compiles fine, but when I run it returns in terminal:

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)

Here is the code:

#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;
}

The txt file I'm using looks like this:

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

So here is what I have found out in researching this problem myself:

  1. EOLs are handled differently by Unix and Windows.
  2. Part of my problem is that:

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

    Is causing the issue, because \n is never found it returns -1, and you can't .erase -1?

I have tried using every conceivable of \r, \n, \r\n, etc. and I always recieve roughly the same output. I have also tried changing the encoding of the .txt file. The only difference is in (which is 14). The number will fluctuate depending on how I encode the .txt file. Also I have opened the .txt file in vim and :set list to see the newline characters. So I know they are there.

This is just partial code of a much larger project for school, and I am not very experienced with c++ yet. Can anyone point me in the right direction? I feel like once I get this portion of my code figured out I should be able to finish the project.

NOTE: the txt file is just an example so do not put too much thought into the size of my arrays or the parameters in my for loop. I have triple checked the sizes of my arrays to make sure there were no issues with me trying to read into a row that didnt exist.


Solution

  • Always check the return of value of find functions. Example:

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

    If \n is not found, the return value is string::npos (it could be 0xFFFFFFFF or 0xFFFFFFFFFFFFFFFF) which is invalid index. Attempting to access that index results in error.

    As noted in comments, names[r] does not contain \n in this case. p is always string::npos and this operation is not required.

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

    You only have 3 integers below each name, so you should count to 3, not 5. This code should work:

    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');
    }
    

    Or you can add more error checking, example if (!(infile >> scores[r][c])) break;