Question

I am trying to make a bank account program that:

Create an account class that has an acct number, a PIN, and a balance. The Acct number and PIN go in through a constructor. The Account number never changes. The PIN can be changed, but only if the correct account number is supplied as an argument. The balance can only be changed if the correct PIN and Account number are submitted as arguments (along with the new balance, of course) to this method. Create a method to print the account number and the current balance together.

so far I have:

#include <iostream>
#include <string>
using namespace std;

//account structure
struct account{
    char accountNumber[10];
    char pin[10];
    double balance;
}account1, account2;

int main() {

    //set account info
    account1.accountNumber = 00011;
    account1.pin = 1234;
    account1.balance = 0.00;

    //set account info
    account2.accountNumber = 00022;
    account2.pin = 4321;
    account2.balance = 100.00;

    //program end
    return 0;
}

//function to change account pin
void changePin(char accountNumber, char pin, char newPin)//PROBLEM
{
    if(strcmp(accountNumber.pin, pin) == 0)
    {
        accountNumber.pin = newPin;
    }
    else
    {
        cout << "Account number or password incorrect.";
    }
}

//change account balance
void changeBalance(char number, char pin, double newBalance)//PROBLEM
{
    if((strcmp(account.pin, pin) == 0) && (strcmp(account.accountNumber, number) == 0))
        {
            account.balance = newBalance;
        }
    else
    {
        cout >> "Account number or pin incorrect.";
    }
}

//function to print account number and balance
void printInfo(char accountNumber)//PROBLEM
{
    cout << "Account Number: " << account.accountNumber;
    cout << "Account Balance: " << account.balance;
}

Now my problem is, I do not know how to reference the account I want in the functions to compare whether the info entered matches the current account info.

EDIT: I am almost done with my program, I am just encountering a problem here:

class Account;
class Account{

public:
    int accountNumber;
    char pin[5];
    double balance;

    void printInfo();
    void changeBalance(int n, char * p, double b);
    void changePin(int n, char * p, char * newPin);
};
void Account::changePin(int n, char * p, char * newPin)
{
    if((n == accountNumber) && (strcmp(p, pin) == 0))
    {
        //pin = newPin;
    }
}

I am trying to write a function that can change the pin number, but I do not know how to write the assignment as I keep getting an error.

Was it helpful?

Solution

Create an account class

A class is very similar to a struct in execution, but conceptually they're a bit different:

In the days of c, you might have some data that belongs together (e.g. Account number, balance, pin), and so you would use a struct to keep it all in one bundle. You can think of this as a (physical) folder in a filing cabinet -- it's all in one place, but it's just a collection of data, nothing more. That's a struct.

In order to use that file folder, you have to get the folder, look at what's in it, and decide what to do with it. There's no real protection of the data in the folder. This is analogous to having a bunch of functions that you can pass an instance of a struct to, and the function can modify the contents of that struct. This is the way things are done in c, but there's no data protection, it can be kind of tedious, and there was a desire for something better.

A class has data and methods. Suddenly, it's not a lifeless file folder to be passed around. Now it's an actual minion - it holds data, but you can also tell it to do something for you, and it knows how to use its own data to accomplish the task. This way, the minion can protect the data from outside interference, and still do useful work.

So, as @Greg suggests, defining a class would be a better approach here. You will want it to contain the data unique to each account, and methods that will do stuff with that data (constructor to initialize it, others to change the PIN and balance, and probably some getters to view the data - or at least something to print it for debugging's sake).

By doing it this way, there's no need for references, but I'm going to talk a bit about data types in a moment, because you appear to be confused about that too.

Data types

Let's look at your account struct:

struct account{
  char accountNumber[10];
  char pin[10];
  double balance;
};

What is balance? It's a floating point number. Which means that it holds a number, which can have a decimal point in it. E.g., it can be 5, 3.7, 3.1415926535898, -123, -2.34, etc. But it cannot be "dog", "cat", nor the letter 'q'.

What are accountNumber and pin? You've created them as arrays of characters (specifically, 10-characters long). What does that mean? Well, they can hold a block of characters, 9 characters or less (remember to leave room for the null terminator). E.g., they can hold "1", "2.3", "1.2.3.4", "dog", "cat", "^&*$^@<>X".

Note that there is a world of difference between 1 and "1". 1 is a number. If we looked inside the computer at all the ones and zeros, it would be stored in memory as something like 00000000 00000000 00000000 00000001. We usually write such number in hexadecimal, because it's shorter, and that looks like: 0x00000001. It's 32-bits long (aka 4-bytes). This is platform-specific, but this is the most common, and should be enough to contrast with the textual "1":

The "1" is two characters: '1' and '\0' (the character -- not number -- one, and a null terminator to end the string). This would be in memory something like this: 00110001 00000000 -- or int hex: 0x3100. Note that this is MUCH shorter (each character is one byte), so "1" is only 2 bytes, while an actual integer is 4 bytes. and that the 1-bit is in a different place. and that '1' is actually hex 0x31!

It is important to understand the difference between character strings and numbers. Basically, character strings are for text (or for printing numbers in human readable format), whereas numeric data types are for actual numeric work.

With that in mind, you might want to rethink your data types here.

Header vs Source, Declaration vs Definition

Something that C++ has that Java lacks, is header files. These can be really tricky and annoying at times, but also rather useful in other ways. Leaving that aside, I'll just focus on the practical aspects of what goes where.

Declarations vs Definitions

First, what is a declaration? It's a way of telling the compiler "I have a thing." That probably seems overly basic, but contrast it with a definition:

A definition is a way of telling a compiler "Here's what the thing looks like.".

So, if you want to create a Function, there's very little that's needed for the declaration:

int AddTheseNumbers(int a, int b);

This tells the compiler enough about AddTheseNumbers that we can now write code that uses it. The compiler knows:

  • The name of the function.
  • The return value of the function - so it knows how much space on the stack to allocate for the return.
  • The parameters (two ints, passed by value) - so it knows how much to push onto the stack before calling the function.

But note what the compiler doesn't know: what the function actually does. That's because the compiler doesn't need to know that. Yes we need it eventually (obviously a program can't run without it), but it's not needed to produce a Foo.obj file (the linker will use it when producing Program.exe).

Now let's look at the definition of that function:

int AddTheseNumbers(int a, int b) {
  return a + b;
}

It's the same signature as the declaration -- that's how the compiler/linker know what we're defining, and now we have the body of the function. The body is the definition.

Headers are for Declarations, Source are for Definitions

So, we could create Simple.h with:

int AddTheseNumbers(int a, int b);

And Simple.cpp with:

int AddTheseNumbers(int a, int b) {
  return a + b;
}

Which we could then compile to create Simple.obj.

Moreover, we can create MyProgram.cpp with:

#include "Simple.h"  // Hey look, I can now use my other file!

int main(int argc, char** argv) {
  std::cout << "Adding 3 + 5: " << AddTheseNumbers(3, 5) << std::endl;
  return 0;
}

And we can compile that into MyProgram.obj. Then we use a linker to link those obj files together, producing MyProgram.exe, which we can then run.

Classes

This gets slightly more complicated with classes. Briefly, for a class Foo, we can do:

class Foo;

This is called a forward declaration, and merely tells the compiler "There's a struct called Foo, but I don't know what's in it". This is useful for passing instances of Foo by reference or pointer, but you can't actually do anything with a Foo, because you don't know what's in it.

class Foo {
  int x;
 public:
  int getX();
};

This is a full declaration of Foo. The compiler knows what data is in it (which is necessary to calculate the full size of Foo), and the method signatures (just like the function declarations above). This is enough to write code that does:

Foo f;
std::cout << f.getX();

And it will compile, because the compiler knows how much memory to allocate for a Foo, and how to interface with it. It doesn't know what getX does, but it doesn't care -- that's the linker's job.

int Foo::getX() {
  return x;
}

This is a definition of Foo's getX method. It's the same signature (returns int, no parameters), and it's scoped to be in Foo itself. Note that this method can simply use x -- the method itself is with an instance of Foo, so it can access everything in that same instance of Foo.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top