-1

I am currently trying to learn C++. I am given a .txt file that contains a different individuals data on each line. I want to read that data into an array of strings. I don't see anything wrong with this function and I have done the same thing before, but for some reason I am receiving a segmentation fault.

#include <string>
#include <iostream>
#include <fstream>

void readFile(std::istream&, std::string*);
int lineCount(std::istream&);

int main(){
    std::ifstream inFile("input.txt");
    int numLines = lineCount(inFile);
    std::string data[numLines];
    inFile.close();
    inFile.open("input.txt");
    readFile(inFile, data);
    inFile.close();
    return 0;
}

int lineCount(std::istream& inFile){
    std::string line;
    int numLines = 0;
    while(std::getline(inFile, line)){
        numLines++;
    }
    return numLines;
}

void readFile(std::istream& inFile, std::string *data){
    int i = 0;
    while(std::getline(inFile, data[i])){
         std::cout << i << "\n"; //testing values
         std::cout << data[i] << "\n"; //testing values
         i++;
    }
}

Here is the output of the above code.

//Output
//Note, these are fictional people
0
Florence,Forrest,1843 Glenview Drive,,Corpus Christi,TX,78401,10/12/1992,5/14/2012,3.215,127/11/1234,2.5,50
1
Casey,Roberta,3668 Thunder Road,,Palo Alto,CA,94306,2/13/1983,5/14/2014,2.978,95
2
Koch,Sandra,2707 Waterview Lane,Apt 302,Las Vegas,NM,87701,6/6/1972,12/14/2015,2.546,69
Segmentation fault //occurs in while condition

Any help would be appreciated

Ean Price
  • 13
  • 3
  • 2
    Who takes care of allocating the memory for that array of strings? You might want to use a std::vector to handle memory management for you. – AlexG Mar 01 '19 at 01:42
  • 1
    Just because a crash happens on one particular line in a C++ program doesn't mean that's where the bug is. C++ does not work this way. The bug can be anywhere. There's nothing obviously wrong with only the shown lines of code; therefore the problem must be related to something else which is not shown. Which is why stackoverflow.com's [help] tells you that you must create a [mcve] before asking for help with your code. Otherwise, it's unlikely that anyone will be able to tell you what's wrong with your program. – Sam Varshavchik Mar 01 '19 at 01:44
  • 1
    Pass in `std::vector& data` and `push_back` into that. This will crash if `data` has not been allocated properly or runs out of space. – tadman Mar 01 '19 at 01:45
  • 1
    One thing you're going to find is that you will almost never see the library functions fail. When you get an error inside a library function the problem is almost always with what the program fed into the library function. Make sure that `inFile`, `data` and `i` are correct. The most likely cause is `i` is larger than the number of elements allocated for `data`. This is where providing a [mcve] comes in handy. – user4581301 Mar 01 '19 at 01:46
  • 1
    Side note: `std::string data[numLines];` is not valid C++, in that the C++ standard doesn't include support for variable-length arrays. It's presumably compiling for you only because your compiler has a non-standard extension to allow it, but you shouldn't rely on it working elsewhere. – Jeremy Friesner Mar 01 '19 at 02:04
  • Use tadman's suggestion if `vector` is permitted on this assignment. If not, make absolutely certain that `lineCount` is correct and not getting fooled by empty lines at the end of the file or a similar bug. If you are not certain you have it right, add `lineCount` to the question. Heck, add it anyway for completeness. – user4581301 Mar 01 '19 at 02:15
  • I'm not permitted to use anything from c++ 11 or higher, but I just added the rest of the code. – Ean Price Mar 01 '19 at 02:21
  • Groovy. Thanks. Sounds like `vector` should be open game. It was formally added to the Standard Library back in 1998. – user4581301 Mar 01 '19 at 02:27
  • I'm not seeing where that screws up unless the file is huge and `std::string data[numLines];` blows past the end of the Automatic storage (probably the stack). – user4581301 Mar 01 '19 at 02:30
  • I triple checked my input.txt file and it has only 3 lines. I printed out the value of numLines that I use as the size of my array and it is 3. Adding one to numLines got rid of the segmentation fault, but I'm not sure that's actually a solution or if it's just a hack. – Ean Price Mar 01 '19 at 02:30
  • Yes. Yes it will. Me am dumb. You still have to have a `data[N]` for that last read with `std::getline(inFile, data[i])` even though the read will fail because of the end of the file. – user4581301 Mar 01 '19 at 02:33

1 Answers1

2

I feel sick that I didn't see this right away.

int numLines = lineCount(inFile);

returns the correct number of lines in the file. Bug's not here, man.

std::string data[numLines];

Is not kosher C++, but will create an array with an element for every line in the file if supported. Your program is running, so it's supported. Still, prefer to use Library Containers.

Meanwhile in readFile...

while(std::getline(inFile, data[i]))

Will try to read a line into data[i]. Whether the read succeeds or not, there must be a data[i] to read into. There won't be for the last try.

The logic goes

  1. read in line 1. Successful, so
  2. read in line 2. Successful, so
  3. read in line 3. Successful, so
  4. read in line 4. Fail. But this does not keep getline from looking off the end of data for a string and going boom (specifically undefined behaviour that manifested as going boom) because there isn't one.

The right solution

int main(){
    std::ifstream inFile("input.txt");
    // no longer need. Vector keeps track for us
    // int numLines = lineCount(inFile);
    std::vector<std::string> data;
    // read nothing from file. Don't need to rewind
    readFile(inFile, data);

    // note: files close themselves when they are destroyed.
    //inFile.close(); 
    return 0;
}
void readFile(std::istream& inFile, std::vector<std::string> & data){
    int i = 0;
    std::string line; // line to read into. Always there, so we don't have to worry.
    while(std::getline(inFile, line)){
         std::cout << i << "\n"; //testing values
         std::cout << line << "\n"; //testing values
         data.push_back(line); // stuff line into vector.
         i++;
    }
}

The No vector Allowed Solution

int main(){
    std::ifstream inFile("input.txt");
    int numLines = lineCount(inFile);
    // legal in every C++, but prefer container may want some extra armour 
    // here to protect from numlines 0. 
    std::string * data = new std::string[numlines]; 
    // the following is a faster way to rewind a file than closing and re-opening
    inFile.clear(); // clear the EOF flag
    inFile.seekg(0, ios::beg); // rewind file.
    readFile(inFile, data);
    inFile.close();
    return 0;
}
void readFile(std::istream& inFile, std::string * data){
    int i = 0;
    std::string line; // same as above. line is here even if data[i] isn't
    while(std::getline(inFile, line)){
         std::cout << i << "\n"; //testing values
         std::cout << line << "\n"; //testing values
         data[i] = line; // stuff line into array. Smart compiler may realize it can move
                         //if not, c++11 adds a formal std::move to force it.
         i++;
    }
}
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Thanks. I am still a bit confused though, because in a very similar program I used the exact same lineCount and readFile functions and it worked. The size of my array was the same as the number of lines in the .txt file, but getline did not cause a seg-fault. – Ean Price Mar 01 '19 at 03:18
  • @EanPrice That's the thing about undefined behaviour. Its behaviour is undefined. Sometimes it getcha, and sometimes it doesn't getcha... yet. Right now at work I'm hunting through some 25 year-old C code that recently got extended with a new menu option.Now it "randomly" locks up on pretty much the other side of the codebase, but only on older CPU boards. There's no debugger for this old beast and adding debug statements changes the code enough that the bug doesn't manifest. I'll find it sooner or later, but UB is evil,man. Evil. – user4581301 Mar 01 '19 at 06:41