Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Objectives: The two main objectives of this project is to test your ability to (

ID: 3903749 • Letter: O

Question

Objectives: The two main objectives of this project is to test your ability to (1) create and use pointers, and (2) create and use C++ classes. A review of your knowledge of structs, arrays, iostream, file I/O and C-style strings is also included.

Description:

This project will expand Project 2 by adding additional functionality, using pointers, and implementing abstract data types (ADTs) through classes. Pointers must be used for all array manipulation, including arrays with ADTs (structs, classes) e.g, rental cars, rental agencies. Pointers must be used in function prototypes and function parameter lists - not square brackets. Make sure all your C-string functions (e.g. string copy, string compare, etc.) work with pointers (parameters list and function implementation). Square brackets are to be used only when declaring an array. For this project, pointers can only be moved by conducting post/pre- increment/decrement operations on them (i.e., ++ or - -), or by setting the pointer back to the base address using the array name. All pointers must be passed by value. (Note: Try to use the arrow operator (->) with Class Object pointers for member access, if you use such in your code.)

The new functionality is as follows: You are given an updated data file (e.g. Agencies.txt) where there are 3 rental Car Agency locations, where each of the 3 locations (RentalAgency) has 5 cars

(RentalCar). You will have similar menu options, but the functionality has been updated below. Note: using multiple helper functions to do smaller tasks will make this project significantly easier. You may want to create a function that will get a car from a location based on the location and car indices.

The RentalCar Class will contain the following data members: Ø m_year, an int (year of production)

m_make, a C-string (char array of 255 maximum size)

m_model, a C-string (char array of 255 maximum size)

m_price, a float (price per day)

m_available, a bool (1 = true; 0 = false; try to display true/false using the

"std::boolalpha" manipulator like: cout<< boolalpha << boolVariable; ) and will have the following methods:

Default Constructor – will set the aforementioned data members to default initial values (Hint: Remember to use properly named constants where appropriate).

Parameterized Constructor – will create a new object based on the values passed into it

(All the above values are expected to be present in the function parameters list, and all should be used to initialize the instantiated Object member variables).

Separate Get and Set methods for all data members.

Print – will print out all the car’s data.

EstimateCost – will estimate the car’s cost given (via a parameter passed to it) a number of days to rent it for.

The RentalAgency ADT will be a struct and will contain the following data members:

name, a C-string (char array of 255 maximum size)

zipcode, an int array of size 5 (Hint: You will NOT be able to use cin and cout –or any fstream objects– directly with this int array as you were doing so far with C-strings. The reason is that reading/writing is specially handled by C++ for char array types. You will

need to manage reading/writing to an int array on your own.) Ø inventory, an array of RentalCar objects with a size of 5

The menu must have the following entries, each implementing a functionality:

1) Ask the user for the input file name, and then read ALL data from that file. Then, read ALL data from that file (the file has been structured where the first line is the Car Agency info, followed by 5 cars). The data have to be stored into arrays of Class Objects.

2) Print out to terminal ALL data for all Agencies and all their corresponding Cars in a way that demonstrates this relationship (see Sample Output section).

3) Estimate car rental cost - prompt for: a) an Agency (e.g., Hertz – you can do so with a

1-3 int number per-Agency), and b) a Car number (where 1-5 are the cars at each agency). Ø 4) Find the most expensive Car – Print to terminal the single most expensive Car out of all 3 Agencies.

5) Print out only the available Cars - from all Agencies, to a separate output file (when the user chooses menu entry 5, they should also get asked for an output file name). Ø 6) Exit program.

The following minimum functionality and structure is required:

Ask the user for the input file name.

The list(s) of cars must be stored into array(s) of Class Objects.

Use character arrays to hold your strings (i.e., C-style) exclusively (using the string data type is still not allowed).

Write multiple functions (Hint: each menu option should be a function).

At least on function must use pass by-Reference. Otherwise, as before, you are free to use pass by-Value, pass by-Reference, pass by-Address for your function parameters. (Note: Remember that using pass by-Value will make the function work on a local internal copy of whatever variable you pass as an argument, therefore the change will not be made on the actual argument itself, and it will be left unaffected after the function call is complete).

Pointers must be used for all array manipulation (iterating over elements to read/modify cannot be performed with bracket operator accessing).

Pointers must be used in function prototypes and function parameter lists (the bracket notation is not allowed in parameters lists).

Pointers can only be moved by incrementing or decrementing: double d[3] = {1,2,3}; double* d_Pt = d;

for (int i=0; i<3; ++i,++d_Pt){ cout << *d_Ptd; }

Or by setting the pointer back to the base address using the array name.

d_Pt = d; cout << *d_Pt << endl;

Write your own C-string copy, C-string compare functions. Their prototypes will have the form (you must use the prototypes exactly as provided, with char      * parameters):

// copies characters from source to destination until a NULLcharacter ‘’ is found in source, then it NULL-terminates destination too, and returns

void myStringCopy(char * destination, const char * source);

// returns 0 when the strings match, i.e. their characters are equal one-by-one until a NULL-character ‘’ is found in both strings and at the same position as well

// returns a value <1 if the first character that does not match has a lower value in str1 than in str2

// returns a value >1 if the first character that does not match has a higher value in str1 than in str2

int myStringCompare(const char * str1, const char * str2);

Ø The other functionality and structure of the program should remain the same as Project #2, including writing to screen and file, as well as restrictions on string libraries, global variables and constants, etc.

Implement the concepts of encapsulation and data hiding as much as possible!

This is a chance to experiment as much as possible with classes, and their concepts as taught in class. It is not a strict requirement that all RentalCar data members are private at this point. Try your best in order to acquaint yourself with these new concepts at this early point, so that it pays off in future project which will impose such hard requirements.

Agencies.txt

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

Explanation / Answer

main.cpp


#include <iostream>
#include <fstream>

#include "RentalCar.h"
#include "RentalAgency.h"

using namespace std;

int menu();
int getIntBetween(int min, int max);
void fiveDigitIntToArray(int fiveDigitInt, int *arr);
void fiveDigitArrayFromFile(int *arr, ifstream &inf);
RentalAgency readRentalAgencyFromFile(ifstream &inf);
RentalAgency readRentalAgencyAndInventoryFromFile(ifstream &inf);
void readAllDataFromFile(RentalAgency * agencies);
void readAllDataFromFile(RentalAgency * agencies, char * filename);
void printRentalAgency(RentalAgency agency);
void printRentalAgencies(RentalAgency * agencies);
RentalCar readRentalCarFromFile(ifstream &inf);
RentalAgency selectAgency(RentalAgency * agencies);
RentalCar selectCar(RentalCar * cars);
void estimateRentalCost(RentalAgency * agencies);
void findMostExpensiveCar(RentalAgency * agencies);
void writeAvailableCarsToFile(RentalAgency * agencies);

// custom string functions
size_t myStringLength(const char * str);
int myStringCompare(const char * str1, const char * str2);
char *myStringCopy(char * destination, const char * source);
char * myStringCat(char * destination, const char * source);


int main() {
    RentalAgency agency;
    RentalAgency agencies[AGENCIES_IN_FILE];
    RentalCar car;
    ifstream inf;
    bool exit = false;
    int selection;

    // TODO: Remove
    readAllDataFromFile(agencies, "Agencies.txt");

    do {
        selection = menu();
        switch (selection) {
            case 1: readAllDataFromFile(agencies); break;
            case 2: printRentalAgencies(agencies); break;
            case 3: estimateRentalCost(agencies); break;
            case 4: findMostExpensiveCar(agencies); break;
            case 5: writeAvailableCarsToFile(agencies); break;
            case 6: exit = true; break;
        }
    } while (!exit);

    return 0;
}

/*
* Display a menu to the user and prompt user for selection
*/
int menu() {
    cout << "What would you like to do?" << endl;
    cout << "1) Read rental agency data from file" << endl;
    cout << "2) Show rental agencies and cars" << endl;
    cout << "3) Estimate car rental cost" << endl;
    cout << "4) Find most expensive car" << endl;
    cout << "5) Write available cars to file" << endl;
    cout << "6) Exit" << endl;

    return getIntBetween(1, 6);
}

/*
* Prompt user for an integer between min and max, inclusive.
* NOTE: This function completely blows up user enters non-integer
*/
int getIntBetween(int min, int max)
{
    int selection;

    // Prompt until valid selection entered
    do {
        cout << "Enter selection (" << min << "-" << max << "): ";
        cin >> selection;   // TODO: Prevent non-integer input infinite loop

    } while (selection < min || selection > max);

    return selection;
}

void fiveDigitIntToArray(int fiveDigitInt, int *arr) {
    int digit;
    int *arrEnd = arr + ZIPCODE_SIZE - 1;

    while (fiveDigitInt >= 10) {
        digit = fiveDigitInt % 10; // Get last digit of base-10 int
        *arrEnd-- = digit;          // Fill array in reverse, because we're pulling digits from the end of fiveDigitInt
        fiveDigitInt /= 10;         // Chop last digit off base-10 int
    }
    *arrEnd = fiveDigitInt;         // At loop end, fiveDigitInt only contains final (first) digit
}

void fiveDigitArrayFromFile(int *arr, ifstream &inf) {
    int fiveDigitInt;
    inf >> fiveDigitInt;
    fiveDigitIntToArray(fiveDigitInt, arr);
}

RentalAgency readRentalAgencyFromFile(ifstream &inf) {
    RentalAgency agency;

    inf >> agency.name;
    fiveDigitArrayFromFile(agency.zipcode, inf);

    return agency;
}

RentalAgency readRentalAgencyAndInventoryFromFile(ifstream &inf) {
    RentalAgency agency;
    RentalCar car;
    RentalCar *inventory = agency.inventory;

    inf >> agency.name;
    fiveDigitArrayFromFile(agency.zipcode, inf);
    for (int i = 0; i < INVENTORY_SIZE; i++) {
        car = readRentalCarFromFile(inf);
        *inventory++ = car;
    }

    return agency;
}

void readAllDataFromFile(RentalAgency * agencies) {
    ifstream inf;
    char filename[MAX_CSTRING_SIZE];

    cout << "Infile name: ";
    cin >> filename;

    inf.open(filename);
    if (inf) {

        for (int i = 0; i < AGENCIES_IN_FILE; i++) {
            RentalAgency & agency = *agencies++;
            agency = readRentalAgencyAndInventoryFromFile(inf);
        }

    } else {
        cerr << "Unable to open file " << filename << endl;
    }

    inf.close();
}

void readAllDataFromFile(RentalAgency * agencies, char * filename) {
    ifstream inf;

    inf.open(filename);
    if (inf) {

        for (int i = 0; i < AGENCIES_IN_FILE; i++) {
            RentalAgency & agency = *agencies++;
            agency = readRentalAgencyAndInventoryFromFile(inf);
        }

    } else {
        cerr << "Unable to open file " << filename << endl;
    }

    inf.close();
}

void printRentalAgency(RentalAgency agency) {
    int *arrPtr = agency.zipcode;
    RentalCar *inventory = agency.inventory;

    // Print name and zipcode
    cout << agency.name << " - ";
    for (int i = 0; i < ZIPCODE_SIZE; i++) {
        cout << *arrPtr++;
    }
    cout << endl;

    // Print inventory
    for (int i = 0; i < INVENTORY_SIZE; i++) {
        inventory->print();
        inventory++;
    }
    cout << endl;
}

void printRentalAgencies(RentalAgency * agencies) {
    for (int i = 0; i < AGENCIES_IN_FILE; i++) {
        printRentalAgency(*agencies++);
    }
}

RentalCar readRentalCarFromFile(ifstream &inf) {
    int year;
    char make[MAX_CSTRING_SIZE], model[MAX_CSTRING_SIZE];
    float price;
    bool available;

    inf >> year >> make >> model >> price >> available;
    RentalCar car(year, make, model, price, available);

    return car;
}

RentalAgency selectAgency(RentalAgency * agencies) {
    int selection;
    RentalAgency agency;
    RentalAgency * agenciesStart = agencies;

    cout << "Please select an agency." << endl;
    for (int i = 0; i < AGENCIES_IN_FILE; i++) {
        cout << i + 1 << ") " << agencies->name << endl;
        agencies++;
    }
    agencies = agenciesStart;   // Reset pointer after iterating
    selection = getIntBetween(1, AGENCIES_IN_FILE) - 1;
    agency = *(agencies + selection);

    return agency;
}

RentalCar selectCar(RentalCar * cars) {
    int selection;
    RentalCar * carsIterator = cars;

    cout << "Please select a car." << endl;
    for (int i = 0; i < INVENTORY_SIZE; i++) {
        cout << i + 1 << ") ";
        carsIterator->print();
        carsIterator++;
    }
    selection = getIntBetween(1, INVENTORY_SIZE) - 1;

    return *(cars + selection);
}

void estimateRentalCost(RentalAgency * agencies) {
    RentalAgency agency;
    RentalCar car;
    int days;

    agency = selectAgency(agencies);
    car = selectCar(agency.inventory);

    cout << "For how many days would you like to rent the " << car.getMake() << " " << car.getModel() << "?" << endl;
    days = getIntBetween(1, 100);
    car.estimateCost(days);
}

void findMostExpensiveCar(RentalAgency * agencies) {
    RentalCar car, mostExpensiveCar = *(agencies->inventory);
    RentalCar * inventory;

    for (int i = 0; i < AGENCIES_IN_FILE; i++) {
        inventory = agencies->inventory;
        for (int j = 0; j < INVENTORY_SIZE; j++) {
            car = *inventory;
            if (car.getPrice() > mostExpensiveCar.getPrice()) {
                mostExpensiveCar = car;
            }
            inventory++;
        }
        agencies++;
    }

    cout << "Most expensive car: ";
    mostExpensiveCar.print();
}

void writeAvailableCarsToFile(RentalAgency * agencies) {
    char filename[MAX_CSTRING_SIZE];
    ofstream of;
    RentalCar car;
    RentalCar * inventory;
    int * zipcode;

    cout << "Name of file to write cars to: ";
    cin >> filename;

    of.open(filename);
    if (of) {

        for (int i = 0; i < AGENCIES_IN_FILE; i++) {
            inventory = agencies->inventory;
            zipcode = agencies->zipcode;

            of << agencies->name << " ";
            for (int k = 0; k < ZIPCODE_SIZE; k++) {
                of << *zipcode++;
            }
            of << endl;

            for (int j = 0; j < INVENTORY_SIZE; j++) {
                car = *inventory;
                if (car.getAvailable()) {
                    of << car.getYear() << " " << car.getMake() << " " << car.getModel() << " " << car.getPrice() << " "
                       << car.getAvailable() << endl;
                }
                inventory++;
            }
            of << endl;
            agencies++;
        }

    } else {
        cerr << "Unable to open file " << filename << endl;
    }

    of.close();
}

// custom string functions
size_t myStringLength(const char * str);
int myStringCompare(const char * str1, const char * str2);
char *myStringCopy(char * destination, const char * source);
char *myStringCat(char * destination, const char * source);


RentalAgency.h

#ifndef SCHOOL_RENTALAGENCY_H
#define SCHOOL_RENTALAGENCY_H

#include "RentalCar.h"

#define MAX_CSTRING_SIZE 255
#define AGENCIES_IN_FILE 3
#define ZIPCODE_SIZE 5
#define INVENTORY_SIZE 5

struct RentalAgency {
    char name[MAX_CSTRING_SIZE];
    int zipcode[ZIPCODE_SIZE];
    RentalCar inventory[INVENTORY_SIZE];
};

#endif //SCHOOL_RENTALAGENCY_H

RentalCar.cpp


#include <iostream>
#include <cstring> // TODO: Remove

#include "RentalCar.h"

using namespace std;

RentalCar::RentalCar() {
    m_year = -1;
    strcpy(m_make, "NOMAKE");
    strcpy(m_model, "NOMODEL");
    m_price = 0;
    m_available = false;
}

RentalCar::RentalCar(int year, const char *make, const char *model, float price, bool available) {
    m_year = year;
    strcpy(m_make, make);
    strcpy(m_model, model);
    m_price = price;
    m_available = available;
}

void RentalCar::print() const {
    cout << m_year << " " << m_make << " " << m_model << ", Price: $" << m_price << ", Available: " << boolalpha
         << m_available << endl;
}

void RentalCar::estimateCost(int days) const {
    cout << "Estimated cost to rent the " << m_make << " " << m_model << " for " << days << " days: $" << m_price * days
         << endl;
}

// Getters
int RentalCar::getYear() const {
    return m_year;
}

char *RentalCar::getMake() {
    return m_make;
}

char *RentalCar::getModel() {
    return m_model;
}

float RentalCar::getPrice() const {
    return m_price;
}

bool RentalCar::getAvailable() const {
    return m_available;
}


RentalCar.h


#ifndef SCHOOL_RENTALCAR_H
#define SCHOOL_RENTALCAR_H

#define MAX_CSTRING_SIZE 255

class RentalCar {
    public:
    // Constructors
    RentalCar();
    RentalCar(int year, const char* make, const char* model, float price, bool available);

    // Getters
    int getYear() const;
    char* getMake();
    char* getModel();
    float getPrice() const;
    bool getAvailable() const;

    // Setters
    void setYear(int year);
    void setMake(char* make);
    void setModel(char* model);
    void setPrice(float price);
    void setAvailable(bool available);

    // Other methods
    void print() const;
    void estimateCost() const;
    void estimateCost(int days) const;

    private:
    int m_year;
    char m_make[MAX_CSTRING_SIZE];
    char m_model[MAX_CSTRING_SIZE];
    float m_price;
    bool m_available;

};


#endif //SCHOOL_RENTALCAR_H

Agencies.txt

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