Search code examples
c++dynamic-data

Why am I getting a EXC BAD ACCESS error when I try to impliment this dynamic array?


Please let me know if I need to provide more/different parts of my program so far if what I've provided isn't enough.

I'm still working on my program with the Airline class. The Airline class contains a vairable to an array of dynamic Flight objects.

In the Airlines class I have (which can't be edited or changed, these are the header files given to me for the assignment):

//Airline.h    
class Airline {
public: 
    Airline();              // default constructor
    Airline(int capacity);  // construct with capacity n
    void cancel(int flightNum);     
    void add(Flight* flight);
    Flight* find(int flightNum);
    Flight* find(string dest);

    int getSize();


private:
    Flight **array;        // dynamic array of pointers to flights
    int capacity;          // maximum number of flights
    int size;              // actual number of flights

    void resize();
};

//Flight.h
    class Flight {
public:
    Flight();
    // Default constructor

    Flight(int fnum, string destination);     
    void reserveWindow();    
    void reserveAisle();
    void reserveSeat(int row, char seat);

    void setFlightNum(int fnum);

    void setDestination(string dest);

    int getFlightNum();

    string getDest();

protected:
    int flightNumber;
    bool available[20][4];    //only four seat types per row; only 20 rows
    string destination;
 };

//Airline.cpp
#include "Airline.h"

/*  Flight **array;        // dynamic array of pointers to flights
    int capacity;          // maximum number of flights
    int size;              // actual number of flights
*/
Airline::Airline(){
    capacity = 1;     
    size = 0;     
    array = new Flight*[1]; 
}

Airline::Airline(int cap){
    capacity = cap;
    size = 0;
    array = new Flight*[capacity];
    //array = &arr;

}

void Airline::cancel(int flightNum){

    for(int i = 0; i < size; i++){
        if(array[i]->getFlightNum() == flightNum){
            array[i] = NULL;
        }
    }

}
    // Delete the flight with the given flight number.
    // Print "Flight cancelled" if successful, or print
    // "No such flight", if the flight cannot be found.

void Airline::add(Flight* flight){
    if(size >= capacity){
        resize();
    }

    array[size] = flight;
    size++;
    cout << array[size]->getFlightNum(); //This is where the EXC BAD ACCESS is. I set the index of the array to point to the address of the flight I sent in, but I can't access it after that...

}
    // Add the given flight to the array.  If there is no room,
    // double the array capacity and copy the existing flights.
    // When increasing the capacity, print "Capacity increased to N",
    // where N is the new capacity.

Flight* Airline::find(int flightNum){
    for(int i = 0; i < size; i++){
        cout << array[i]->getFlightNum();
        if(array[i]->getFlightNum() == flightNum){
            return array[i];
        }
    }

        return 0;

}
    // Return pointer to flight with given number if present, otherwise
    // return 0.
Flight* Airline::find(string dest){
    for(int i = 0; i < size; i++){
        if(array[i]->getDest() == dest){
            return array[i];
        }
    }

        return 0;
}
    // Return pointer to flight with given destination if present, 
    // otherwise return 0.

int Airline::getSize(){
    return size;
}
    // Returns the number of Flights in the array.

void Airline::resize(){
    Flight **temp = new Flight*[capacity * 2];
    Flight **swapper;
    for(int i = 0; i < capacity; i++){
        temp[i] = array[i];
    }

    swapper = temp;
    temp = array;
    array = swapper;
    delete [] temp;

    capacity *= 2;
    cout << "Capacity increased to " << capacity << endl;
}
    // resizes the array if it exceeds capacity.  New array is double size of old array.

//Flight.cpp
#include "Flight.h"

/*  int flightNumber;
    bool available[20][4];    //only four seat types per row; only 20 rows
    string destination;
*/


Flight::Flight(){
    flightNumber = 0;
    destination = "X";
    for(int i = 0; i < 20; i++){
        for(int j = 0; j < 4; j++)
            available[i][j] = false;
    }
}
    // Default constructor
Flight::Flight(int fnum, string dest){
    flightNumber = fnum;
    destination = dest;
    for(int i = 0; i < 20; i++){
        for(int j = 0; j < 4; j++)
            available[i][j] = false;
    }

}
    // initialize flight with flight number and destination

void Flight::reserveWindow(){
    int i, j;
    char seat;
        bool reserved = false;
            for(i = 0; i < 20; i++){
                for(j = 0; j < 4; j++){
                    if (j == 0 || j == 3){
                        if(!available[i][j] && !reserved){
                            available[i][j] = true;
                            reserved = true;
                            break;
                        }
                    }
                }
                if(reserved)
                    break;
            }
    if (!reserved) {
        cout << "Not available" << endl;
    }else
        switch (j) {
            case 0:
                seat = 'A';
                break;
            case 4:
                seat = 'D';
                break;
            default:
                break;
        }
    cout << "Reserved " << i << seat << endl;
}
    // If a window seat if available, reserve the first available
    // seat, and print it.  The first available seat is the 
    // lowest-numbered one in the lowest numbered row. Seat 0, is
    // A, since 1 is B, and so on.
    // If the seat reserved is 7D, for example, print "7D".
    // If no such seat is available, print "Not available".

void Flight::reserveAisle(){
        bool reserved = false;
    int i, j;
    char seat;
        for(i = 0; i < 20; i++){
                for(j = 0; j < 4; j++){
                    if (j == 1 || j == 2){
                        if(!available[i][j] && !reserved){
                            available[i][j] = true;
                            reserved = true;
                            break;
                        }
                    }
                }
            if(reserved)
                break;
        }
    if (!reserved) {
        cout << "Not available" << endl;
    }else
        switch (j) {
            case 1:
                seat = 'B';
                break;
            case 2:
                seat = 'C';
                break;
            default:
                break;
        }
        cout << "Reserved " << i << seat << endl;
}
    // Just like reserveWindow, but for aisle seats. 

void Flight::reserveSeat(int row, char seat){
        bool reserved = false;
    if (row > 20 || row < 1 || seat > 'D' || seat < 'A') {
        cout << "No such seat." << endl;
        return;
    }
        for(int i = 0; i < 20; i++){
                for(int j = 0; j < 4; j++){
                        if(!available[i][j] && !reserved){
                            available[i][j] = true;
                            reserved = true;
                            break;
                        }
                    }
            if(reserved)
                break;
        }
    if (!reserved) {
        cout << "Not available" << endl;
    }else
        cout << "Reserved " << row << seat << endl;

}
    // Reserve the seat specified if available.  If it is available,
    // print it as in reserveWindow.  
    // If it does not exist, print "No such seat".  
    // If it exists, but is unavailable, print, "Not available".

void Flight::setFlightNum(int fnum){
    flightNumber = fnum;
}
    //assign the flight number for this flight

void Flight::setDestination(string dest){
    destination = dest;
}
    //assign the destination (airline code) for this flight

int Flight::getFlightNum(){
    return flightNumber;
}
    // Return the flight number

string Flight::getDest(){
    return destination;
}
    // Return the destination

//main.cpp
#include "Airline.h"
#include "Flight.h"
#include <fstream>
#include <iomanip>


using namespace std;

int main(){
    ifstream in;
    Airline airline(10);
    Flight flight;
    Flight* flightTemp;
    string transaction;
    string transType;
    int flightNum;
    string flightDest;
    string seatType;
    int seatRow;
    char seatCol;
    string dummy;

    in.open("input4.txt");
    if(!in){
        cout << "File not found. Ending program." << endl;
        return 1;
    }

    while(in >> transaction){
        if(transaction == "ADD"){
            in >> dummy >> flightNum >> dummy >> flightDest;
            //flight(flightNum,flightDest);
            flight.setFlightNum(flightNum);
            flight.setDestination(flightDest);
            airline.add(&flight);
            cout << flight.getFlightNum(); //It works here...

        }
        else if(transaction == "CANCEL"){
            in >> dummy >> flightNum;
            airline.cancel(flightNum);
        }else{

            in >> transType;

            if(transType == "Flight"){
                in >> flightNum;
                cout << flightNum;
                flightTemp = airline.find(flightNum);
            }else{
                in >> flightDest;
                flightTemp = airline.find(flightDest);

            }

        in >> seatType;

        if(seatType == "Seat"){
            in >> seatRow >> seatCol;
            flightTemp->reserveSeat(seatRow - 1, seatCol - 1);

        }else if(seatType == "Aisle"){
            flightTemp->reserveAisle();
        }else
            flightTemp->reserveWindow();

        }
    }

    in.close();
    cin.get();
    return 0;
}

EDIT I added all my code Just to make it easier.

The problem I'm having now is when I run try to access the flightNum (or any getter method)in a Flight in my array. I set the index of the array to point to the address of the flight I sent in in the add() method, but I can't access it after that...


Solution

  • With your constructor:

    Airline::Airline(){
        capacity = 1;
        size = 0;
        Flight* arr = new Flight[capacity];
        array = &arr;
    }
    

    What's this?

    Flight* arr = new Flight[capacity];
    array = &arr;
    

    Allocate array the same way you do in resize:

    Airline::Airline(){
        capacity = 1;
        size = 0;
        array = new Flight*[1];
    }
    

    Since array is an array of Flight*, not a pointer to an array of Flight

    EDIT: After your edit, here is another problem in your code:

    void Airline::add(Flight* flight){
        if(size >= capacity){
            resize();
        }
    
        array[size] = flight;
        size++;
        cout << array[size]->getFlightNum(); 
    }
    

    You're doing array[size]->getFlightNum(); after you've incremented size when you're printing the flight number. Swap size++ and cout << array[size]->getFlightNum();:

    void Airline::add(Flight* flight){
        if(size >= capacity){
            resize();
        }
    
        array[size] = flight; 
        cout << array[size]->getFlightNum();
        size++;
    }
    

    EDIT2: Your Airline::cancel function is also problematic:

    void Airline::cancel(int flightNum){
        for(int i = 0; i < size; i++){
            if(array[i]->getFlightNum() == flightNum){
                array[i] = NULL;
            }
        }
    }
    

    You can't just set a position in the array to NULL to remove a Flight from the array. A common method is replacing that position in the array with the last element, then decrement the size:

    void Airline::cancel(int flightNum){
        for(int i = 0; i < size; i++){
            if(array[i]->getFlightNum() == flightNum){
                array[i] = array[--size];
            }
        }
    }
    

    Flight::reserveWindow also causes a seg fault and chances are there's still more bugs in the code. I'll let you go from here since it's homework.