-1

I am making a program to create and edit bank accounts.

I'm trying to use accountNum as a variable to specify the array's size. It is declared as a global variable, and I don't get any errors running the code. The code works when I tell it to create a bank account, but after entering the name of the account, it says segmentation fault.

The array is an array of objects if that effects anything.

This is the code that prints Segmentation Fault

#include <iostream>

int accountNum = 0;

class bank {
    
    int balance;
    std::string ownedBy;

    public:

    bank() {
      accountNum++;
  }

    void setOwnership() {
            balance = 0;
            std::cout << "Enter the name of this bank account's owner: \n";
            std::cin >> ownedBy;
    }
    
    friend std::ostream& operator<<(std::ostream& os, const bank& dt);
        
};

std::ostream& operator<<(std::ostream& os, const bank& dt) {
        os << dt.balance;
        return os;
    }

int main() {
    int j = 0;
    int a;
    int st1;
    
    //Array for objects from the bank class
    bank bankAccounts[accountNum];
    
    for(;;) {
        std::cout << "What would you like to do today?\n";
        std::cout << "Enter 1 to create a bank account\n";
        std::cout << "Enter 2 to access a bank account\n\n";
        
        std::cin >> st1;
        if (st1 == 1) {
            
            int n = 1;
            for(int i = 0; i < n; i++){
                
                bankAccounts[j].setOwnership();
                std::cout << "You have succsesfully created your bank account!\n\n";
                n++;
                j++;
                break;
            }
          } else if (st1 == 2) {

            std::cout << "Please choose which bank account you would like to access\n\n";

            for(int i = 0; i < accountNum; i++) {
                std::cout << i+1 << ". ";
                bankAccounts[i].printOwnership();
            }
            
            std::cin >> a;
            bankAccounts[a-1].checkOwnership();
            bankAccounts[a-1].checkBalance();
            break;
         }
       }
            

It the code works up until it says "Enter the name of the bank accounts owner". I enter the name and it says segmentation fault.

I've tried declaring the variable in the class, and in main, but that just creates errors.

Why is it doing this and how could I fix it?

  • 1
    In C++, arrays are fixed size and for arrays defined like `bank bankAccounts[size];` size must be a compile time constant. Some compilers will allow using a non-compile time constant as an extension - outside the standard language. Even if you are using that "feature" that is not officially part of C++, at the time of that definition, the variable has a value of 0, so you are creating an array with NO elements. – Avi Berger Mar 17 '23 at 04:07
  • 3
    Consider, at the moment the line `bank bankAccounts[accountNum];` is executed, what is the value of `accountNum`? – TheUndeadFish Mar 17 '23 at 04:10
  • Dear bank: Please segfault _after_ paying off my mortgage, but _before_ deducting that from my account. [Boomshanka, Neil](https://www.youtube.com/watch?v=BZHvqZhWcUE). – paddy Mar 17 '23 at 04:21
  • If `accountNum` is the number of `bank`s you've created, what do you expect it to be in `bank bankAccounts[accountNum];`, before you've created any `bank`s? – molbdnilo Mar 17 '23 at 04:38
  • The `setOwnership` loop is very strange. It breaks out on the first iteration, and if it didn't it would never terminate. What was the purpose of writing a loop there? – molbdnilo Mar 17 '23 at 04:40
  • Before I've created anything in bank I don't expect anything to be there. Before I just had the array size as 30, but when I went to print out all the banks there were a bunch of blank slots. `accountNum` was meant to increase the size of the array every time an account was created so it wouldn't print the blank slots. I didn't realize that you couldn't change the size of a array. – Emery Gonzalez Mar 17 '23 at 12:14

1 Answers1

1

Your problem lies with the fact that you're trying to give an imaginary variable some data to save. Let me clarify below:

The root of your problem is this line in your current code:

int n = 1;
            for(int i = 0; i < n; i++){

                bankAccounts[j].setOwnership(); //<-- THIS LINE
                std::cout << "You have succsesfully created your bank account!\n\n";
                n++;
                j++;
                break;
            }
          } else if (st1 == 2) {

or more precisely bankAccounts[j]

Lets look at this in a simpler fashion:

You have an array of lets say int values: int tab[10]. This array has as you can see 10 values aka 10 variables inside it. When using this table, you have to use its name and index of the value/variable however you want to call it you want to use. eg: tab[0] = 3 will set the first element of the arrayto number 3. Now if you try doing this outside the scope of the array (i mean below 0 or higher than the size of the table) youll get an error because you defined the array to have 10 values with indexes from 0 to 9 thus int 10 for array doesnt exist.

Now what you have in your example is an array. arrays, if not used dynamically, have static sizes meaning sizes you cannot change. So if you define int accountNum = 0; and then use it to create array bank bankAccounts[accountNum]; what you're left with is an array of size 0 meaning its empty and you can't change its size during the run of the program. Even if you add to the accountNum anywhere in the code, the array has already been created and the size of it wont change. on a simpler example it would look something like this:

int n = 0;
int tab[n];

No matter what where after the creation of tab we try to change value of n, the tab will always have 0 elements.

Which basically is the same as typing int tab[0];. which also means there is no index in there, not even index 0 that you can use to save data inside. If you change this number accountNum to lets say 1, your program will work without crashing, or at least it did for me in QT environment.

Now onto the solutions. The solution to your problem is to just have something with dynamic sizes preferably to first not have to use global variables and second, to make your code well work. You have a few options to do this. One of the most basic ones is a dynamic array but to do that you'll need to do a little research yourself. The better solution and easier is in my opinions vectors<> which will enable you to do what you're doing in minimalistic amounts of lines of code. What i mean is:

This is your example 1:1 using vectors (which have dynamic sizes)

#include <iostream>
#include <vector> //this is needed. Note that we dont need an AccountNum variable to set size of vector
class bank {
    int balance;
    std::string ownedBy;

    public:

    bank()
    {

    }
    void setOwnership() {
        balance = 0;
        std::cout << "Enter the name of this bank account's owner: \n";
        std::cin >> ownedBy;
    }
    friend std::ostream& operator<<(std::ostream& os, const bank& dt);

};

std::ostream& operator<<(std::ostream& os, const bank& dt)
{
    os << dt.balance;
    return os;
}

int main() {
    int j = 0;
    int a;
    int st1;

    //Array for objects from the bank class
    std::vector<bank> bankAccounts; //we create vector of type bank.
// Note that vector size starts at 0

    for(;;) {
        std::cout << "What would you like to do today?\n";
        std::cout << "Enter 1 to create a bank account\n";
        std::cout << "Enter 2 to access a bank account\n\n";

        std::cin >> st1;
        if (st1 == 1) {

            int n = 1;
            for(int i = 0; i < n; i++){
                bank newAccount; //we create new Account
                newAccount.setOwnership(); //set the values
                bankAccounts.emplace_back(newAccount); //add it to vector
                std::cout << "You have succsesfully created your bank account!\n\n";
                n++;
                j++;
                break;
            }
          } else if (st1 == 2) {

            std::cout << "Please choose which bank account you would like to access\n\n";

            for(int i = 0; i < bankAccounts.size(); i++) { //note vectors have size function to tell you the size of it. you can use this to loop through its items
                std::cout << i+1 << ". ";
                //bankAccounts[i].printOwnership();
            }

            std::cin >> a;
            //bankAccounts[a-1].checkOwnership();
            //bankAccounts[a-1].checkBalance();
            break;
         }
       }
}

Extras: I recommend using do while loop switch cases instead of empty for loop for statements for a form of menu:

#include <iostream>
#include <vector>
class bank {
    int balance;
    std::string ownedBy;

    public:

    bank()
    {

    }
    void setOwnership() {
        balance = 0;
        std::cout << "Enter the name of this bank account's owner: \n";
        std::cin >> ownedBy;
    }
    friend std::ostream& operator<<(std::ostream& os, const bank& dt);

};

std::ostream& operator<<(std::ostream& os, const bank& dt)
{
    os << dt.balance;
    return os;
}

int main() {
    int choice;
    //Array for objects from the bank class
    std::vector<bank> bankAccounts;

    do
    {
        std::cout << "What would you like to do today?\n";
        std::cout << "Enter 1 to create a bank account\n";
        std::cout << "Enter 2 to access a bank account\n\n";

        std::cin >> choice;
        switch(choice)
        {
        case 1:
        {
            bank newAccount;
            newAccount.setOwnership();
            bankAccounts.emplace_back(newAccount);
            std::cout << "You have succsesfully created your bank account!\n\n";
            break;
        }
        case 2:
        {
            std::cout << "Please choose which bank account you would like to access\n\n";

            for(int i = 0; i < bankAccounts.size(); i++) {
                std::cout << i+1 << ". ";
                //bankAccounts[i].printOwnership();
            }
            int a;
            std::cin >> a;
            //bankAccounts[a-1].checkOwnership();
            //bankAccounts[a-1].checkBalance();
            break;
        }
        }
    }while(choice != 0);
}

Monogeon
  • 346
  • 1
  • 9