0

This is my text file:

12345 shoe 5 0   
34534 foot 72 1   
34562 race 10 0 
34672 chicken 24 150
88 pop 65 0

I need to take this file and go row by row, assign the first number as an identifier itemNum, second word as itemName, third number as itemPrice, and last number as itemAdjusmentValue. I will need to perform arithmetic with the last two numbers itemPrice and itemAdjusmentValue.

Code so far:

using namespace std;

// making a struct to store each value of the cuadre

struct Cuadre 
{

    int itemNum;
    string itemName;
    int itemPrice;
    int itemAdjusment;

};

int main (){

    ifstream infile("sheet_1.txt");
    string checkLine;

    if (infile.is_open()){

        while ( infile.good()){

            getline (infile, checkLine);
            cout << checkLine << endl;
        }
    }
    else 
        cout << "error with name of file" << endl;


    vector<Cuadre> procedures;

    Cuadre line;

    while(Cuadre >> line.itemNum >> line.itemName >> line.itemPrice >> line.itemAdjusment){
        procedures.push_back(line);
    }

This code generates an error on the last while statement

expected primary-expression before '>>' token

I cant really find a specific tutorial on how to do this, and i've looked a good amount.

Barmar
  • 596,455
  • 48
  • 393
  • 495

4 Answers4

1

From the code you posted, (with reference to the >> istream operators) it looks like you want to stream the contents of the string data read from your file into the members of a struct.

It is not possible to stream directly from a std::string (eg: checkLine >> x >> y >> z), as string does not provide a streaming interface.

In order to do that you need to use a stream, such as std::stringstream. You could populate a with your string checkLine, and then stream from that into your data members

std::stringstream ss(checkLine);
ss >> line.itemNum >> line.itemName >> line.itemPrice >> line.itemAdjusment;

Example code:

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>

using namespace std;

// making a struct to store each value of the cuadre

struct Cuadre
{

    int itemNum;
    string itemName;
    int itemPrice;
    int itemAdjusment;

};

int main (){

    ifstream infile("sheet_1.txt");
    string checkLine;

    vector<Cuadre> procedures;

    if (infile.is_open()){

        while ( infile.good()){

            getline (infile, checkLine);
            cout << checkLine << endl;

            Cuadre line;
            std::stringstream ss(checkLine);
            ss >> line.itemNum >> line.itemName >> line.itemPrice >> line.itemAdjusment;
            procedures.push_back(line);
        }
    }
    else
        cout << "error with name of file" << endl;

    return 0;
}
Steve Lorimer
  • 22,912
  • 14
  • 99
  • 180
1

You need to push into the vector inside the loop that reads from the file. And you should be getting the fields from checkLine -- Cuadre is a type name, not a variable you can read from. But to do that you need to create a stringstream.

int main (){

    ifstream infile("sheet_1.txt");
    string checkLine;
    vector<Cuadre> procedures;

    if (infile.is_open()){

        while (getline (infile, checkLine)){
            Cuadre line;
            cout << checkLine << endl;
            stringstream linestream(checkline);
            if (linestream >> line.itemNum >> line.itemName >> line.itemPrice >> line.itemAdjusment) {
                procedures.push_back(line);
            } else {
                cout << "incorrect line" << endl;
                break;
            }                
        }
    }
    else {
        cout << "error with name of file" << endl;
    }
}

while (infile.good()) is also not correct, it's essentially the same as while (!infile.eof()). See Why is iostream::eof inside a loop condition considered wrong?

Barmar
  • 596,455
  • 48
  • 393
  • 495
  • `std::string` does not offer a streaming interface. You'll need to populate a stringstream first, and use that – Steve Lorimer Nov 20 '17 at 16:25
  • thanks, fixed. For some reason I thought something like this had been added to the language (using the extract operator with a string would create the stream automatically). – Barmar Nov 20 '17 at 16:28
1

You can try reading directly into struct as well:

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

struct Cuadre
{
    int itemNum;
    std::string itemName;
    int itemPrice;
    int itemAdjusment;
};

int main() 
{
    std::vector<Cuadre> procedures;
    std::ifstream infile("sheet_1.txt");

    while (infile)
    {
        Cuadre line;
        if (infile >> line.itemNum >> line.itemName >> line.itemPrice >> line.itemAdjusment)
            procedures.push_back(line);
        else
            break;
    }

    if (!procedures.empty())
    {
        for (auto &p : procedures)
            std::cout
            << "itemNum: " << p.itemNum << "\t"
            << "itemName: " << p.itemName << "\t"
            << "itemPrice: " << p.itemPrice << "\t"
            << "itemAdjusment: " << p.itemAdjusment
            << std::endl;
    }
    else
        std::cout << "error with file or data" << std::endl;

    return 0;
}

Prints:

itemNum: 12345  itemName: shoe  itemPrice: 5    itemAdjusment: 0
itemNum: 34534  itemName: foot  itemPrice: 72   itemAdjusment: 1
itemNum: 34562  itemName: race  itemPrice: 10   itemAdjusment: 0
itemNum: 34672  itemName: chicken       itemPrice: 24   itemAdjusment: 150
itemNum: 88     itemName: pop   itemPrice: 65   itemAdjusment: 0
Killzone Kid
  • 5,839
  • 3
  • 12
  • 33
1

If you define an overload of >> for your type Cuadre, you can read directly from the file into Cuadre objects.

std::istream& operator>>(std::istream& is, Cuadre & cuadre)
{
    std::string s;
    getline(is, s);
    std::cout << s;
    std::stringstream ss(s);
    ss >> cuadre.itemNum >> cuadre.itemName >> cuadre.itemPrice >> cuadre.itemAdjusment;
    return is;

    // or without logging

    return is >> cuadre.itemNum >> cuadre.itemName >> cuadre.itemPrice >> cuadre.itemAdjusment;
}

int main (){

    ifstream infile("sheet_1.txt");
    vector<Cuadre> procedures;

    for (Cuadre line; infile >> line;) {
        procedures.push_back(line);
    }

    // or with #include <algorithm>

    std::copy(std::istream_iterator<Cuadre>{ infile }, {}, std::back_inserter(procedures));
}
Caleth
  • 35,377
  • 2
  • 31
  • 53
  • This is nice code. The only improvement I'd make is to make the `operator>>` overload read into a local `Cuadre` (or into four local variables) and then set the members of `cuadre`, so that the `cuadre` parameter is only populated if all fields can be read successfully. – Jonathan Wakely Nov 20 '17 at 16:50