Search code examples
c++readfilecoredump

c++ split a file into records when blank space is found?


I have a file like this

2.7388  0 2.4670
3.6384  1 24.5927
8.7844  0 10.6871
11.2892 0 2.6507
19.6054 1 16.8974
25.8811 0 8.0084

For example i'll take the first row 2.7388 0 2.4670 . Im trying to accomplish something like the following

2.7388 = double x
0      = int y
2.4670 = double z

My attempt

struct fileReader{
double x;
int y;
double z;
};

std::vector<fileReader> afileReader(std::string fileName) {

  std::vector<fileReader> readtheFile;
  std::ifstream List;
  std::string line;
  List.open(fileName);
 char delimiter = ' '; //delimiter added

  while (std::getline(List, line))
  {
    line.pop_back();
    std::string token;
    std::istringstream ss(line);
    fileReader afileReader;

    std::getline(ss, token,delimiter);
    afileReader.x = std::stod(token); //change from stoi to stod
 
    std::getline(ss, token,delimiter);
    afileReader.y = std::stoi(token);

    std::getline(ss, token,delimiter);
    afileReader.z = std::stod(token); //change from stoi to stod
    readtheFile.push_back(std::move(afileReader));
  }

for(fileReader x: readtheFile) {
      std::cout << x.x;
      std::cout << x.y;
      std::cout << x.z;
  }
  return readtheFile;
  passengerList.close();

}

When i run this from main running a line afileReader("file.txt") . I get the following error

terminate called after throwing an instance of 'std::invalid_argument'
  what():  stod //error changed
Aborted (core dumped) 

Im not sure why im getting an error for stoi as its the correct conversion method to convert the int value to the string(as token is a string)

To refer back to the question though I wish to split the record when a blank space is hit. So refering back to the previous example of 2.7388 0 2.4670 , when 2.7388 is read its assigned to variable x, when 0 is read its assigned to varible y and 2.4670 is assigned to variable z


Solution

  • (Recommended) More direct way to do this :

    #include <fstream>
    #include <iostream>
    #include <vector>
    
    struct Data {
      double x;
      int y;
      double z;
    };
    
    std::vector<Data> fileReader(std::string fileName) {
    
      std::vector<Data> result;
      std::ifstream file(fileName);
    
      Data data;
    
      while (file >> data.x >> data.y >> data.z)
        result.push_back(data);
    
      for (auto &&i : result)
        std::cout << i.x << ' ' << i.y << ' ' << i.z << '\n';
    
      return result;
    }
    
    int main() { fileReader("test.txt"); }
    

    Sample Run


    Problems with your original code :

    1. fileReader::x and fileReader::z were not floating-type numbers.
    2. ' ' was not being passed as delimiter in call to std::getline.
    3. Inconsistent spacing in the file you were reading. (FIX)
    4. For some strange reason you were doing line.pop_back();
    5. [Cause of certain warning] You weren't returning anything from afileReader() (non-void function).

    Fixed code :

    #include <fstream>
    #include <iostream>
    #include <istream>
    #include <sstream>
    #include <vector>
    
    struct fileReader {
      double x;
      int y;
      double z;
    };
    
    std::vector<fileReader> afileReader(std::string fileName) {
    
      std::vector<fileReader> readtheFile;
      std::ifstream List(fileName);
      std::string line;
    
      while (std::getline(List, line)) {
    
        std::string token;
        std::istringstream ss(line);
        fileReader afileReader;
    
        ss >> std::ws;
        std::getline(ss, token, ' ');
        afileReader.x = std::stod(token);
    
        ss >> std::ws;
        std::getline(ss, token, ' ');
        afileReader.y = std::stoi(token);
    
        ss >> std::ws;
        std::getline(ss, token);
        afileReader.z = std::stod(token);
    
        readtheFile.push_back(std::move(afileReader));
      }
    
      for (auto &&i : readtheFile)
        std::cout << i.x << ' ' << i.y << ' ' << i.z << '\n';
    
      return readtheFile;
    }
    
    int main() { afileReader("test.txt"); }