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

#ifndef CREDIT_ACCOUNT_H #define CREDIT_ACCOUNT_H class CreditAccount { private:

ID: 3794149 • Letter: #

Question

#ifndef CREDIT_ACCOUNT_H
#define CREDIT_ACCOUNT_H

class CreditAccount
{
private:
char accountNo[20];
char custName[20];
double creditLimit;
double currentBalance;
public:
CreditAccount();
CreditAccount(char accNo[20],char name[20],double limit, double balance);
char* getAccountNumber();
char* getName();
double getLimit();
double getBalance();
void processPayment(double amount);
bool processCharge(double amount);
void print();
  
};
#endif

CreditAccount.cpp

#include <iostream>
#include<string.h>
#include "CreditAccount.h"
using namespace std;


CreditAccount::CreditAccount()
{
accountNo[0]='';
custName[0] = '';
creditLimit = 0;
currentBalance = 0;
}
CreditAccount::CreditAccount(char accNo[20],char name[20],double limit, double balance)
{
strcpy(accNo,accountNo);
strcpy(name,custName);
creditLimit = limit;
currentBalance = balance;
}
char* CreditAccount::getAccountNumber()
{
return accountNo;
}
char* CreditAccount::getName()
{
return custName;
}
double CreditAccount::getLimit()
{
return creditLimit;
}
double CreditAccount::getBalance()
{
return currentBalance;
}
void CreditAccount::processPayment(double amount)
{
currentBalance = getBalance()-amount;
}
bool CreditAccount::processCharge(double amount)
{
if((amount+currentBalance)> getLimit())
return false;
else
{
currentBalance = getBalance()+amount;
return true;
}
}
void CreditAccount::print()
{
cout<<"Account Number: "<<accountNo<<endl;
cout<<"Name: "<<custName<<endl;
cout<<"Credit Limit: $"<<creditLimit<<endl;
if(currentBalance < 0)
cout<<"Current Balance: $"<<(-1)*(currentBalance)<<" CR"<<endl;
else
cout<<"Current Balance: $"<<currentBalance<<endl;

}

AccountDB.h

#ifndef ACCOUNT_DB_H
#define ACCOUNT_DB_H

#include "CreditAccount.h"
#include<string>
class AccountDB
{

private:
CreditAccount acc[20];
int count;

public:
AccountDB();
AccountDB(const char*);
void print();
};
#endif

AccountDB.cpp

#include "AccountDB.h"
#include<string>
#include<fstream>
#include<iostream>
using namespace std;

AccountDB::AccountDB()
{
count = 0;
}
AccountDB::AccountDB(const char* s)
{
ifstream inFile;
inFile.open(s,ios::in| ios::binary);
inFile.read((char*)this, sizeof(AccountDB));
inFile.close();
}
void AccountDB::print()
{
cout<<"Credit Card Account Listing "<<endl;
for(int i = 0;i<count;i++)
{
acc[i].print();
cout<<endl;
  
}
}

assign2.cpp

#include <iostream>
#include "CreditAccount.h"
#include "AccountDB.h"
using std::cout;
using std::endl;

int main()

{

AccountDB db("accounts");
db.print();
return 0;

}

I have this so far and this is part 2:

For this part of the assignment, you'll need to write one new file and then modify two of the files you wrote for Part 1.

Step 1: Write a makefile

The file named makefile tells the make utility how to build the final executable file from your collection of C++ source code and header files. The makefile for this assignment is given in its entirety below. Makefiles for future assignments will follow this basic pattern.

IMPORTANT NOTE: The commands that appear in the makefile below MUST be indented as shown. Furthermore, the indentation MUST be done using a tab character, not spaces. If you don't indent your makefile commands, or indent using spaces, your makefile WILL NOT WORK.

Once you've written the file makefile, try using the make utility to compile and link your program.

Step 2: Add the following methods to the AccountDB class

sortAccounts() - This method takes no parameters and returns nothing.

This method should sort the array of CreditAccount objects in ascending order by account number using the insertion sort algorithm.

The sort code linked to above sorts an array of integers called numbers of size size. You will need to make a substantial number of changes to that code to make it work in this program:

This will be a method, not a function. Change the parameters for the method to those described above.

In the method body, change the data type of bucket to CreditAccount. This temporary storage will be used to swap elements of the array of CreditAccount objects.

In the method body, change any occurrence of numbers to the name of your array of CreditAccount objects and size to numAccounts (or whatever you called the data member that tracks the number of valid CreditAccount objects stored in the array).

The comparison of accountArray[j-1] and bucket will need to use the C string library function strcmp() to perform the comparison. Also, you'll need to use the getAccountNumber() method to access the accountNumber data member within each CreditAccount object. The final version of the inner for loop should look something like this:

It is legal to assign one CreditAccount object to another; you don't need to write code to copy individual data members.

Add a call to the sortAccounts() method to the end of the alternate constructor you wrote for the AccountDB class. This will sort the array of CreditAccount objects that were read in from the input file.

searchForAccount() - This method should take one parameter: a character array containing the account number code of the CreditAccount to search for (searchNumber). The method should return an integer.

The logic for this method is a variation of the binary search of a sorted list strategy.

As usual, you'll need to use strcmp() to perform the comparison of account numbers.

processTransactions() - This method should take one parameter: a C++ string containing the name of a file of credit card transaction data. The method should return nothing.

The method should open the specified transaction file for input (not binary input - this file is a text file). Make sure to test that the file was opened successfully; if it wasn't, print an error message and exit the program.

Before reading any transactions, the function should print a report header and column headers. The function should then read transaction data from the file until end of file is reached. A typical transaction is shown below. The first field on the transaction record is the date of the transaction, followed by an account number, then the transaction type ('C' for charge or 'P' for payment), and finally a transaction amount.

Once all of the data for a given transaction has been read, call the searchForAccount() method to search the accounts array for the account number given in the transaction. If the account number is present in the array, then the transaction may be processed. For a payment, simply call the processPayment() method for the object that contains a matching account number, passing it the transaction amount. For a charge, call the processCharge() method for the object that contains a matching account number, passing it the transaction amount.

For each transaction record processed, print a line in a transaction report with the data from the record and the updated balance for that account. If the balance is negative, it should be printed as a positive number but followed by the letters "CR". If the transaction account number was not found in the account array or if a charge exceeded the account's credit limit (i.e., if the processCharge() method returned false), print an appropriate error message instead of the account balance.

After all transactions have been processed, close the transaction file.

Step 3: Add two method calls to the main program

The main() routine logic will now look like this:

Create an AccountDB object using the alternate constructor you wrote. Pass the filename string "accounts" as an argument to the constructor.

Call the print() method for the AccountDB object.

Call the processTransactions() method for the AccountDB object. Pass the filename string "transactions.txt" as an argument to the method.

Call the print() method for the AccountDB object.

Explanation / Answer

Assignment Overview

In Part 2 of this assignment, you will add some functionality to the AccountDB class and add some logic to your main() routine to test that functionality.

Purpose

This part of the assignment introduces the insertion sort and binary search algorithms. It also introduces the use of makefiles for compiling and linking your programs.

Set Up

In your Assignment 2 directory, make a symbolic link to the data file for this part of the assignment:

In this assignment, you will be creating several source code and header files, as described below. You can create each of these files separately using the nano editor, just as you did on Assignment 1.

Once you've written a makefile for your program, you can compile and link it by simply typing:

Running the executable file is unchanged from Part 1.

To remove the executable and object code files for your program (conserving disk space), you can type:

Program

For this part of the assignment, you'll need to write one new file and then modify two of the files you wrote for Part 1.

Step 1: Write a makefile

The file named makefile tells the make utility how to build the final executable file from your collection of C++ source code and header files. The makefile for this assignment is given in its entirety below. Makefiles for future assignments will follow this basic pattern.

IMPORTANT NOTE: The commands that appear in the makefile below MUST be indented as shown. Furthermore, the indentation MUST be done using a tab character, not spaces. If you don't indent your makefile commands, or indent using spaces, your makefile WILL NOT WORK.

Once you've written the file makefile, try using the make utility to compile and link your program.

Step 2: Add the following methods to the AccountDB class

sortAccounts() - This method takes no parameters and returns nothing.

This method should sort the array of CreditAccount objects in ascending order by account number using the insertion sort algorithm.

The sort code linked to above sorts an array of integers called numbers of size size. You will need to make a substantial number of changes to that code to make it work in this program:

This will be a method, not a function. Change the parameters for the method to those described above.

In the method body, change the data type of bucket to CreditAccount. This temporary storage will be used to swap elements of the array of CreditAccount objects.

In the method body, change any occurrence of numbers to the name of your array of CreditAccount objects and size to numAccounts (or whatever you called the data member that tracks the number of valid CreditAccount objects stored in the array).

The comparison of accountArray[j-1] and bucket will need to use the C string library function strcmp() to perform the comparison. Also, you'll need to use the getAccountNumber() method to access the accountNumber data member within each CreditAccount object. The final version of the inner for loop should look something like this:

It is legal to assign one CreditAccount object to another; you don't need to write code to copy individual data members.

Add a call to the sortAccounts() method to the end of the alternate constructor you wrote for the AccountDB class. This will sort the array of CreditAccount objects that were read in from the input file.

searchForAccount() - This method should take one parameter: a character array containing the account number code of the CreditAccount to search for (searchNumber). The method should return an integer.

The logic for this method is a variation of the binary search of a sorted list strategy.

As usual, you'll need to use strcmp() to perform the comparison of account numbers.

processTransactions() - This method should take one parameter: a C++ string containing the name of a file of credit card transaction data. The method should return nothing.

The method should open the specified transaction file for input (not binary input - this file is a text file). Make sure to test that the file was opened successfully; if it wasn't, print an error message and exit the program.

Before reading any transactions, the function should print a report header and column headers. The function should then read transaction data from the file until end of file is reached. A typical transaction is shown below. The first field on the transaction record is the date of the transaction, followed by an account number, then the transaction type ('C' for charge or 'P' for payment), and finally a transaction amount.

Once all of the data for a given transaction has been read, call the searchForAccount() method to search the accounts array for the account number given in the transaction. If the account number is present in the array, then the transaction may be processed. For a payment, simply call the processPayment() method for the object that contains a matching account number, passing it the transaction amount. For a charge, call the processCharge() method for the object that contains a matching account number, passing it the transaction amount.

For each transaction record processed, print a line in a transaction report with the data from the record and the updated balance for that account. If the balance is negative, it should be printed as a positive number but followed by the letters "CR". If the transaction account number was not found in the account array or if a charge exceeded the account's credit limit (i.e., if the processCharge() method returned false), print an appropriate error message instead of the account balance.

After all transactions have been processed, close the transaction file.

Step 3: Add two method calls to the main program

The main() routine logic will now look like this:

Other Points

As always, programs that do not compile on turing/hopper automatically receive 0 points.

Make sure to document your program according to the standards listed in the Course Notes book. In particular, each function or method should have a documentation box describing the purpose of the function, the input parameters, and the return value (if any). There should also be a documentation box for the program as a whole.

Submit the final version of your program using the electronic submission guidelines posted on the course web site and described in class.

1. A sample makefile and how it works

Let's start by looking at a sample makefile:

Note that the arrows -> represent places where you should put tab characters, not eights spaces. It hath been decreed that this shalt be a tab character. Emacs and XEmacs have a makefile mode, which you can get into by typing M-x makefile-mode if it doesn't come up automatically. In makefile mode, pressing the tab key inserts a real tab. Alternatively, the keystrokes C-q C-i or C-q tab will enter a tab character in any mode. (C-q is emacs for quote next key unprocessed.)

You should name your makefile `Makefile' with that capitalization. Make looks for that file automatically. If you don't name it that, you'll have to tell make specifically which file to use (as in gmake -f somethingelse ...).

1.1 The short answer

The short answer of how to use that makefile is this: Change the line that says SRC_FILES = so that the right-hand side of the equals sign is a list of all the .cc files in your project. Change the line that says EXEC = so that the right-hand side of the equals sign is the name of your executable.

The first time you use make, add a .cc file, or any time you change whether a .cc file includes a particular .h file, run the command:

To build your executable in general, run the command gmake. To clean up your directory and get rid of files you don't need, run gmake clean.

These short directions will be enough to get you through the first assignment or two, but after that, you'll probably need to start changing more stuff further down in the makefile, and to know what to do, you'll have to understand how make works. So, without further ado...

1.2 Comments

Any line which begins with a sharp sign (#) is ignored by the makefile as a comment. Comment lines can be used to leave instructions for whoever has to use your makefile (including yourself). They are also useful for allowing someone to select between alternative definitions of macros. For example, several lines of the makefile have been commented out here:

The idea is that you should un-comment exactly one definition for COURSE_DIR and LIB_DIR, depending on which computer system you're using. By keeping these alternatives in the file with all but one hidden, you make it easier on yourself to move your project from one network to another.

1.3 Continuing long lines

Continuing long lines is easy, just put a backslash at the end of the line. Make pretends the following long command is all on one line:

Make replaces the backslashes with a space when it combines the lines, so just don't break a line in the middle of a word.

1.4 Macros

In a makefile, it is very easy to define a macro, or text-substitution. These are similar to environment variables in the shell or string variables in most programming languages:

Whenever make sees $(COURSE_DIR) in the makefile, it will substitute in the text contained in the macro COURSE_DIR. Remember, use the dollar sign and parentheses only when you want to reference the macro. Just use its name to assign it a value.

One really useful thing about macros is that they can reference other macros:

The trick is that make doesn't substitute for DEBUG_LEVEL immediately when you define CXXFLAGS. Instead, when you reference CXXFLAGS, it expands into $(DEBUG_LEVEL) $(EXTRA_CCFLAGS). Since that still has$'s in it, make expands it again into -g -Wall. Therefore, you can define macros in any order, as long as they are defined before they are actually expanded.

1.5 Special $ commands

One line of the sample makefile illustrates a special command that make provides through the $ symbol:

This particular line sets O_FILES to be the same as SRC_FILES but with all the .cc suffixes replaced with .o. This is useful because you can easily add a new class to your project by adding its .cc filename to the definition of SRC_FILES. Its object file will automatically be added to O_FILES. This means that adding a file to your project requires changing only one line in your makefile. Furthermore, having a list of all source and object files is quite useful, as you'll soon see.

1.6 Basic dependency rules

Dependency rules are statements that make uses to determine which files need to be brought up to date. They consist of a line declaring what target file depends on which dependencies, followed by zero or more command lines which tell it what to do to bring the target up to date. For example (from another makefile):

The executable usepix is the target and all those .o files are the dependencies. The $(CXX) line turns into a command to g++ when all those macros are expanded.

Again I must say, it hath been declared that command lines shalt begin with a tab character and end with a new-line character. If the last line of your makefile is not doing anything, it may be that you forgot to push enter at the end of that line.

The dependency line states that the file usepix depends upon the files in the macro OBJ, which in this case expands to application.o, menu.o, etc. If you ask make to update usepix by entering the command gmake usepix on the shell command line, it will find this dependency line and look at all the .o files usepix depends upon. If one of them is determined to be out of date, it is updated. If after all that one of those .o files is newer than usepix, or if usepix doesn't exist, make will execute the compilation command underneath the dependency line and build an up-to-date version of usepix. You may have as many command lines as you want, as long as they all begin with tab characters. You may also have zero command lines, which is useful for pseudo-targets and implicit rules, which I will explain later. All those macros are fully expanded before make looks at any dependencies.

1.7 Special dependency rules

The first dependency is magic. When you execute make, it expects you to give it the name of a target to update on the command line, ie.gmake usepix. If you don't give a target, it simply updates the first target it comes to. In the first sample makefile, it's all, and in the smaller second example, it's usepix, but in a larger project, there might be several test programs, libraries, and so on. It's therefore common to have a first target called `all' which depends on the files you want to update most frequently. No file named `all' ever really exists because it is a pseudo-target. Which brings us to the next item...

Pseudo-targets are really useful. A pseudo-target is a file which never really exists. It has a dependency section in the makefile, and if you tell make to update that target, it will do its normal stuff and update all the dependencies, then run any commands underneath the dependency line.

Here's an example that uses a pseudo-target to effectively combine two other targets so that you can update them with one command:

Issuing the command gmake testsuite causes make to update test1 and test2.

Another way to use pseudo-targets is to have a target which has no dependencies but has a few commands listed under it. In the sample makefile, `clean' is just such a pseudo-target:

Targets which have no dependencies are always considered out of date and any commands listed under them are always executed. If you were to issue the command gmake clean using the sample makefile, make would remove all those .o files from the current directory.

Having a `cleanup' target or two is quite useful: You're not likely to mistype gmake clean and even if you did, it wouldn't be a disaster. But notice how easy it is to mistype rm -f *.o (remove all your .o files) as rm -f *>o (remove everything and re-direct any output into a file called o). Holding down the shift key a moment too long can wipe out weeks of work, and make can easily prevent such goofs.

Here are some sample pseudo-targets that are useful for lots of different things. Note that some macros are used that you'll have to define for yourself elsewhere:

1.8 Special macros

Now all those $@ thingees that appear in the example above and elsewhere in the makefile are clearly not plain old macros, since they're never defined and yet this makefile works quite well, I promise. The reason is that there are a number of special macros with one character names that are only useable as part of a dependency rule:

$@

The file name of the target.

$<

The name of the first dependency.

$*

The part of a filename which matched a suffix rule.

$?

The names of all the dependencies newer than the target separated by spaces.

$^

The names of all the dependencies separated by spaces, but with duplicate names removed.

$+

The names of all the dependencies separated by spaces with duplicate names included and in the same order as in the rule.

Some of these are only useful as part of suffix rules which are described in section Suffix rules.

1.9 Suffix rules

Most of the commands you use to update files are similar; to build most C++ programs, you call g++ with similar flags and really just change the name of the file you're compiling. Make allows you to define suffix rules so that you don't have to put command lines underneath all your dependencies. For example, here is the built-in suffix rule that gmake uses to compile a .cc file into a .o file:

With suffix rules, you can leave out the command part of a dependency rule, for example:

If make decides to update usepix.o, it sees from this line that it depends on usepix.cc, and it sees from the %.cc: %.o rule that to update it, it should run g++ using the flags defined in CXXFLAGS and to compile usepix.cc.

Make has a number of built in suffix rules, which are roughly as follows:

You can get the full list from the command gmake -p -f/dev/null/.