I have a program with car rental information and the company as well. I am trying to read it in and have it display on the terminal. However, I am only getting one company to print clearly, while the others print out only trash. I want to store the agencies with a car inventory of 5 as well, but don't exactly know how to store them without having all my information read in yet. I can only use C-Style strings also.
Here is the file I am reading in:
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
Section of my code where I need help:
#include <iostream>
#include <fstream>
using namespace std;
struct car
{
char agency[10];
int zip;
int year;
char make[10];
char model[10];
float price;
int available;
} ;
struct agency
{
char company[10];
int zip;
int inventory[5];
};
void menu();
// Main Function
int main ()
{
// declare variables
const int carAmount = 15;
int agencyAmount = 1;
int choice;
agency agencyLib[carAmount];
car carLib[carAmount];
char filename[10];
ifstream carInData;
bool menu1 = false;
//prompt user for input file
cout << " Enter file name: ";
cin >> filename;
// Start loop menu
while(menu1 = true)
{
menu();
carInData.open(filename);
cin >> choice;
if (carInData.is_open())
{
// read list of names into array
for (int count = 0; count < agencyAmount; count++)
{
carInData >> agencyLib[count].company >> agencyLib[count].zip;
for (count = 0; count < carAmount; count++)
{
carInData >> carLib[count].year >> carLib[count].make >> carLib[count].model >> carLib[count].price >> carLib[count].available;
}
}
}
switch (choice)
{
// Case 1 closes menu
case 1:
return 0;
break;
// Case 2 displays if car is available if 1, unavailable if 0
case 2:
// itterate through car array
for(int count = 0; count < agencyAmount; count++)
{
cout << agencyLib[count].company << " " << agencyLib[count].zip << "\n";
for(int count = 0; count < carAmount; count++)
{
// Displays if car is available or not
/* if (carLib[count].available == 1)
cout << " Available ";
else
cout << " Unavailable ";
*/
// Display Cars
cout << carLib[count].year << " " << carLib[count].make << " " << carLib[count].model << " " << carLib[count].price << " " << "\n";
}
}
}
}
}
As a general preliminary remark, I think that even for learning purpose, this kind of exercise should better let you use std::strings
instead of c-strings and std::vector
for keeping a growing number of items.
The first problem is that you use the same counter count
to populate your agency array AND the car array. This will cause you very quickly to have a counter beyond the array boundaries and corrupt memory.
Solution: rework your loop structure using 2 distinct counters.
Next problem is that you don't identify the end of the car list of an agency. This makes it unrealistic to read more than one agency: you'll experience a failure on the stream reading that will prevent you getting anything usefull in your data.
Solution: analyze failures on reading to identify going from cars ( first element should be a number) to a new agency ( first element is a string).
In addition, you might have some strings which are longer than allowed by your character arrays, causing further memory corruption.
Solution: limit the number of chars read using iomanip() to fix maximum width. This is strongly recommended unless you go for std::string
Last issue: the variable length arrays are not a standard C++ feature, even if some popular compilers support it.
Solution: Either use dynamic allocation with new/delete or opt for the purpose of this excercise to use a constant maximum size.
Adapted, without choices, menus, etc. , the reading would look like:
const int carAmount = 30; // !!!
const int agencyAmount = 10; // !!!
agency agencyLib[carAmount];
car carLib[carAmount];
ifstream carInData ("test.dat");
int numCar = 0, numAgency = 0; // !!! shows the real number of items available
int count1, count2; //
cout << "Start reading" << endl;
for (numAgency = numCar = 0; carInData && numAgency < agencyAmount; numAgency++) {
if (!(carInData >> setw(sizeof(agencyLib[numAgency].company)) >> agencyLib[numAgency].company >> agencyLib[numAgency].zip))
break; // if nothing left, exit loop immediately
for (; numCar < carAmount; numCar++) {
carInData >> carLib[numCar].year >> setw(sizeof(carLib[numCar].make )) >>carLib[numCar].make
>> setw(sizeof(carLib[numCar].model))>>carLib[numCar].model
>> carLib[numCar].price >> carLib[numCar].available;
if (carInData.fail()) { // here we expect a year, but get an agency string
carInData.clear();
break;
}
strcpy(carLib[numCar].agency, agencyLib[numAgency].company);
carLib[numCar].zip = agencyLib[numAgency].zip;
}
}
And the subsequent display:
cout << "Display agencies: " << endl;
for (count1 = 0; count1 < numAgency; count1++) {
cout << agencyLib[count1].company << " " << agencyLib[count1].zip << "\n";
}
cout << "Cars: " << endl;
for (count2 = 0; count2 < numCar; count2++) {
cout << carLib[count2].agency << " " << carLib[count2].zip << ": ";
cout << carLib[count2].year << " " << carLib[count2].make << " " << carLib[count2].model << " " << carLib[count2].price << " " << "\n";
}
Note that there's no link beteween agencies and cars (except the common fields), so the display just shows two distinct lists.