62626368616e
62626368616e

Reputation: 321

Read data from a file into struct and add struct to a vector (to create a vector of structs)

This question has been asked before but the other question/answers used concepts I'm not yet familiar with in C++.

I need to read data from a file into a vector of structs.

I have the following code but I'm confused about what to put in (....), that is if I have the correct logic.

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

struct Parts{
        std::string partNum;
        char partClass;
        int stock;
        float cost;
};

bool readFile(std::vector <Parts>&);
int displayMenu();

int main(){
        std::vector <Parts> pVector;

        readFile(pVector);

        if (!readFile(pVector)){
                std::cout << "Error reading file!" << std::endl;
        }
        else{
                displayMenu();
        }
        return 0;
}

bool readFile(std::vector <Parts> &pVector){
        std::ifstream inputFile("parts.txt");
        if (inputFile.fail()){
                std::cout << "Error reading file!" << std::endl;
                return false;
        }
        else{
                while (....){
                        pVector.emplace_back(....);
                }
                return true;
        }
}

Sample lines from the file:

P-42936 A 18 129.79
P-43179 A 47 35.60
P-43264 B 31 103.81
P-43367 B 5 32.39
P-43378 A 46 6.38
P-43622 A 10 155.36

Upvotes: 1

Views: 424

Answers (2)

bruno
bruno

Reputation: 32586

You want that :

bool readFile(std::vector <Parts> &pVector){
  std::ifstream inputFile("parts.txt");

  if (inputFile.fail()){
    std::cout << "Error reading file!" << std::endl;
    return false;
  }
  else {
    Parts part;

    while (inputFile >> part.partNum >> part.partClass >> part.stock >> part.cost)
      pVector.emplace_back(part);
    return true;
  }
}

In main you call two time the read function :

   readFile(pVector);

   if (!readFile(pVector)){

very probably the first call must be removed

It can be also interesting to define the operator >> for Parts rather than to have the code doing that in readFile

So :

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

struct Parts{
  std::string partNum;
  char partClass;
  int stock;
  float cost;
};

std::istream & operator >>(std::istream & is, Parts & part) {
  if (is >> part.partNum >> part.partClass >> part.stock)
    is >> part.cost;

  return is;
}

bool readFile(std::vector <Parts>&);
//int displayMenu();

int main(){
  std::vector <Parts> pVector;

  if (!readFile(pVector)){
    std::cout << "Error reading file!" << std::endl;
  }
  else{
    //displayMenu();
    // to check, of course operator << can be defined too
    for (auto p : pVector)
      std::cout << p.partNum << '/' << p.partClass << '/' << p.stock << '/' << p.cost << std::endl;
  }
  return 0;
}

bool readFile(std::vector <Parts> &pVector){
  std::ifstream inputFile("parts.txt");

  if (inputFile.fail()){
    std::cout << "Error reading file!" << std::endl;
    return false;
  }
  else {
    Parts part;

    while (inputFile >> part)
      pVector.emplace_back(part);
    return true;
  }
}

Compilation and execution:

pi@raspberrypi:/tmp $ g++ -Wall r.cc
pi@raspberrypi:/tmp $ cat parts.txt 
P-42936 A 18 129.79
P-43179 A 47 35.60
P-43264 B 31 103.81
P-43367 B 5 32.39
P-43378 A 46 6.38
P-43622 A 10 155.36
pi@raspberrypi:/tmp $ ./a.out
P-42936/A/18/129.79
P-43179/A/47/35.6
P-43264/B/31/103.81
P-43367/B/5/32.39
P-43378/A/46/6.38
P-43622/A/10/155.36
pi@raspberrypi:/tmp $ 

Upvotes: 3

Ted Lyngmo
Ted Lyngmo

Reputation: 117238

I suggest adding overloads for operator>> and operator<<:

#include <iostream>
#include <string>
#include <vector>

struct Part {            // I renamed it because it only holds info about one part
    std::string partNum;
    char partClass;
    int stock;
    float cost;
};

std::istream& operator>>(std::istream& is, Part& p) {
    return is >> p.partNum >> p.partClass >> p.stock >> p.cost;
}

std::ostream& operator<<(std::ostream& os, const Part& p) {
    return os << p.partNum << ' ' << p.partClass << ' ' << p.stock << ' ' << p.cost;
}

This makes extracting or printing one Part easy:

bool readFile(std::vector<Part>& pVector){
    std::ifstream inputFile("parts.txt");
    if(inputFile) {
        Part tmp;
        while(inputFile >> tmp)        // extract one Part at a time using operator>>
            pVector.emplace_back(tmp);
        return true;
    } else {
        std::cout << "Error reading file!" << std::endl;
        return false;
    }
}

Upvotes: 3

Related Questions