whiteferrari
whiteferrari

Reputation: 5

How to read data from text file into int array of struct?

I've created a RentalAgency struct which contains a name, zip code, and inventory. I've also created a RentalCar class which contains the members of the inventory. I'm trying to read in the data from the text file into each respective place and I'm having trouble with it.

struct RentalAgency {
    char name[25]; //25 characters max
    int zipcode[5]; //5 digits in zipcode
    RentalCar inventory[5]; //5 cars
};


class RentalCar {
    int m_year;
    char m_make[256], m_model[256]; //256 characters max
    float m_price;
    bool m_available;

    public:
    RentalCar();
    RentalCar(int, char[], char[], float, bool);
    void setYear(int);
    void setMake(char[]);
    void setModel(char[]);
    void setPrice(float);
    void setAvailable(bool);
    int getYear();
    char* getMake();
    char* getModel();
    float getPrice();
    bool getAvailable();
    void print();
    float estimateCost(int);
};

I'm attempting to read from this text file.

Hertz 93619
2014 Toyota Tacoma 115.12 1
2012 Honda CRV 85.10 0
2015 Ford Fusion 90.89 0
2013 GMC Yukon 110.43 0
2009 Dodge Neon 45.25 1   

Alamo 89502
2011 Toyota Rav4 65.02 1
2012 Mazda CX5 86.75 1
2016 Subaru Outback 71.27 0
2015 Ford F150 112.83 1
2010 Toyota Corolla 50.36 1

Budget 93035
2008 Ford Fiesta 42.48 0
2009 Dodge Charger 55.36 1
2012 Chevy Volt 89.03 0
2007 Subaru Legacy 59.19 0
2010 Nissan Maxima 51.68 1  

So far I've set up a function to read the data. I've managed to create a for loop that reads in the Rental Agency name, but I get stuck when it comes to the zip code.

void input(struct RentalAgency data[])
{
    char inputFile[50]; //50 characters max
    char tmp;
    std::ifstream inputStream;

    std::cout << "Enter input file name: ";
    std::cin >> inputFile;

    inputStream.open(inputFile);

    for(int i = 0; i < 3; i++) //3 agencies 
    {   
        inputStream >> data[i].name;

        for(int j = 0; j < 5; j++)
        {
            inputStream >> tmp;

            data[i].zipcode[j] = tmp;   
        }
    }

}

My output when I print the data is:

data[0].name = Hertz //correct
data[0].zipcode[0] = 57 //wrong
data[0].zipcode[1] = 51 //wrong
data[0].zipcode[2] = 54 //wrong
data[0].zipcode[3] = 49 //wrong
data[0].zipcode[4] = 57 //wrong

What I want is:

data[0].zipcode[0] = 9
data[0].zipcode[1] = 3
data[0].zipcode[2] = 6
data[0].zipcode[3] = 1
data[0].zipcode[4] = 9

Upvotes: 0

Views: 83

Answers (2)

A M
A M

Reputation: 15277

Please find below a full working solution, including the nonesense constraints from yout instructor.

So, we do here, what normally nobody would do.

  • Usage of char arrays instead of strings (Why that? What a nonesense)
  • Using plain old C-style arrays
  • using magic numbers for array dimensions instead of dynamic sizes.
  • using of raw pointer!
  • using setters and getters for everthing, braking encapsualtion
  • returning pointer to member variables

Thsi program is stongly dependent on the exact input format, which is also not good.

A more flexible approach would be better

#include <iostream>
#include <sstream>
#include <fstream>
#include <iterator>
#include <algorithm>

std::istringstream inputFile{ R"(Hertz 93619
2014 Toyota Tacoma 115.12 1
2012 Honda CRV 85.10 0
2015 Ford Fusion 90.89 0
2013 GMC Yukon 110.43 0
2009 Dodge Neon 45.25 1

Alamo 89502
2011 Toyota Rav4 65.02 1
2012 Mazda CX5 86.75 1
2016 Subaru Outback 71.27 0
2015 Ford F150 112.83 1
2010 Toyota Corolla 50.36 1

Budget 93035
2008 Ford Fiesta 42.48 0
2009 Dodge Charger 55.36 1
2012 Chevy Volt 89.03 0
2007 Subaru Legacy 59.19 0
2010 Nissan Maxima 51.68 1
)" };

constexpr size_t MakeAndModelSize = 256;
constexpr size_t MaxInputLineSize = 1024;
constexpr size_t ZipCodeSize = 5;
constexpr size_t InventorySize = 5;
constexpr size_t NameOfAgenySize = 25;

class RentalCar {

public:
    RentalCar() {
        std::fill(m_make, m_make + MakeAndModelSize, 0);
        std::fill(m_model, m_model + MakeAndModelSize, 0);
    };
    RentalCar(int y, char* make, char* model, float price, bool available) : m_year(y), m_price(price), m_available(available)  {
        std::copy_n(make, MakeAndModelSize, m_make);
        std::copy_n(model, MakeAndModelSize, m_model);
    }

    // I am breaking the whole encapsulation 
    // We make some more noensense and define setters and getters for everything. 
    // so, we can also make all data public . . .
    void setYear(int year) { m_year = year; }
    void setMake(char* make) { std::copy_n(make, MakeAndModelSize, m_make); } 
    void setModel(char* model) { std::copy_n(model, MakeAndModelSize, m_model); }
    void setPrice(float price) { m_price = price; }
    void setAvailable(bool avail) { m_available = avail; }
    int getYear() { return m_year; };
    char* getMake() { return m_make; }; 
    char* getModel() { return m_model; } 
    float getPrice() { return m_price;  }
    bool getAvailable() { return  m_available; };
    void print() { std::cout << *this;  } // This function is not needed. We overlaoded the inserter already for that purpose
    double estimateCost(int days) { return days * m_price * (m_available ? 1.0 : 0.0);}

    // Overload inserter and extractor
    friend std::ostream& operator << (std::ostream& os, const RentalCar& rc) {
        return os << rc.m_year << ' ' << rc.m_make << ' ' << rc.m_model << ' ' << rc.m_price << ' ' << rc.m_available;
    }

    friend std::istream& operator >> (std::istream& is, RentalCar& rc) {
        is >> rc.m_year >> rc.m_make >> rc.m_model >> rc.m_price >> rc.m_available;
        return is;
    }

protected:
    // The data of the car
    int m_year{};
    char m_make[MakeAndModelSize];   // Lord, forgive me, I am using a fixed size plain char array for a string
    char m_model[MakeAndModelSize];  // Lord, forgive me, I am using a fixed size plain char array for a string
    float m_price{ 0.0 };
    bool m_available{ false };
};


class RentalAgency {

public:
    // Extractor operator. Read all data from stream
    friend std::istream& operator >> (std::istream& is, RentalAgency& ra) {
        is >> ra.name ;
        std::copy_n(std::istream_iterator<char>(is), ZipCodeSize, ra.zipcode);
        // Read all inventory data
        std::copy_n(std::istream_iterator<RentalCar>(is), InventorySize, ra.inventory);
        return is;
    }

    // Inserter operator. Output Data
    friend std::ostream& operator << (std::ostream& os, const RentalAgency& ra) {

        // Show name and zip code
        os << ra.name << ' ';
        std::copy_n(ra.zipcode, ZipCodeSize, std::ostream_iterator<char>(os));
        os << '\n';
        // Print inventory data
        std::copy_n(ra.inventory, InventorySize, std::ostream_iterator<RentalCar>(os, "\n"));
        return os << '\n';
    }

protected:
    char name[NameOfAgenySize]{};
    int zipcode[ZipCodeSize]{};
    RentalCar inventory[InventorySize]{};
};

int main()
{
    RentalAgency ra1{};
    RentalAgency ra2{};
    RentalAgency ra3{};

    // Read all data
    inputFile >> ra1 >> ra2 >> ra3;

    // For verification. Write all data to std::cout
    std::cout << ra1 << ra2 << ra3;

    return 0;
}

Please note. I am overloading the extractor and inserter operator for the classes. With that, reading and writing is extremely easy. Please see in main.

Then I read from an istringstream. But that is the same as reading from a file. Here on SO I do not have files, so I choose this solution.

Upvotes: 0

Ted Lyngmo
Ted Lyngmo

Reputation: 117258

You are storing the ASCII values for the characters 0 - 9 in the zip code. You need to subtract the ASCII value for 0 from the character you read:

for(int j = 0; j < 5; j++)
{
    inputStream >> tmp;
    data[i].zipcode[j] = tmp - '0';
}

Upvotes: 1

Related Questions