UQ Students should read the Disclaimer & Warning
Note: This page dates from 2005, and is kept for historical purposes.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>COMP2301 - Assignment 4 - File I/O in C++</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
<!--
.wrong {
background: #FF9999;
}
body {
background: url(_img/DSC04989.jpg) fixed center;
font-family: "Arial Unicode MS", Arial, Helvetica, sans-serif;
}
th, td, textarea {
border: 1px solid #000000;
padding: 0 1ex;
background: transparent;
overflow: hidden;
}
table {
border: none;
}
-->
</style>
</head>
<body>
<h1>COMP2301 – Assignment Four – File I/O in C++</h1>
<p> This assignment is a pass/fail assignment. I achieved a pass.</p>
<p>The goal of this assignment is to gain experience using C++ for object-oriented
programming. </p>
<p> In this assignment, you will become familiar with: </p>
<ul>
<li>C++ I/O methods: operator << and operator >> </li>
<li>Use of classes in C++ </li>
<li>Some aspects of the standard template library (STL) </li>
</ul>
<h2>Specification </h2>
<p>Develop a command-line program to read and manipulate a file of internet banking
transactions. Each individual transaction starts on a new line and contains
six comma separated transaction details. </p>
<ol>
<li> Timestamp: 10-digit: [yymmddhhnnss], [yy] = year, [mm] = month,
[dd] = day, [hh] = hour (from [00] to [23]), [nn] = minutes, [ss] = seconds. </li>
<li> Customer’s last name: </li>
<li> Customer reference number: 10-digit number. </li>
<li> Account type : “Check” for (Checking account), “Sav” for (Savings account)
or “Cred” for (Credit card account). </li>
<li> Transaction type : “Dep” for (Deposit) or “With” for (Withdrawal). </li>
<li> Transaction amount: [dollars.cc], where [dolars] = integer dollars and [cc]
= integer cents. </li>
</ol>
<p>Example input file containing four transaction: <em>( Timestamp,
Customer’s last name, customer reference number, Account type , Transaction
type , Transaction amount ) </em><br />
<textarea name="a" cols="82" rows="4" readonly="readonly" title="Sample Input File">0405031220, Howard, 6434199921, Check, With, 230.20
0405040936, Schwarzenegger, 4873123321, Sav, Dep, 5000000.00
0405031322, Jackson, 3856927195, Cred, With, 2500.00
0405051816, Schwarzenegger, 4873123321, Sav, With, 2000000.00 </textarea>
</p>
<h2>Functions required for the command line interface </h2>
<ul>
<li> The program sorts the transactions when run from the command line in three
ways: <br />
transactionlist [ [/t] | [/n] | [/c] ] INPUTFILE [OUTPUTFILE] <br />
/t
[DEFAULT] : sort transactions in Numeric order by Time Stamp <br />
/n :
sort transactions in Alphabetic order by Last Name <br />
/c :
sort transactions in Numeric order by Time Stamp of combined deposit balance </li>
<li> An error is generated if more than one command line switch is entered. </li>
<li> If no command line switch is entered the default operation executes and
the program writes the sorted transactions to standard output (cout). </li>
<li> If an [OUTPUTFILE] is specified the program writes the sorted transactions
to the named file. Existing file content should be overwritten. </li>
<li> If [/c] the combined balance switch is entered all transactions with identical
customer reference numbers AND identical account types must be combined into
one transaction.
<ul>
<li> Time stamp of the combined transaction = Time stamp of the last transaction
that corresponds to the appropriate customer reference number and account
type </li>
<li> Transaction type of the combined transaction is “CombDep” (CombinedDeposit) </li>
<li> Transaction amount is the [sum of all appropriate deposits] - [sum of
all appropriate withdrawals] </li>
</ul>
</li>
<li> You are to implement the operator <<, operator >>, operator
/=, operator + and comparison operators.
<ul>
<li> operator <<, operator >> are to be used to read the file
and write to cout. </li>
<li> operator /= is used to test if two transactions have identical
customer reference numbers AND account types. </li>
<li> operator + combines two transactions. </li>
</ul>
</li>
</ul>
<h2>General </h2>
<ul>
<li> You will need to write a class called “transaction” in this assignment. </li>
<li> You must <strong>NOT</strong>use stdio.h (i.e. scanf, printf, etc.). </li>
<li> You may use strcpy, sscanf, and other string manipulation routines included
in string.h. </li>
<li> You <strong>MUST</strong> use the Standard Template Library’s list (or
vector). </li>
<li> Running your program with no command line parameters must generate a usage
statement. </li>
<li> All transactions with identical customer reference numbers have identical
last names </li>
<li> Transaction amount for a combined balance may be negative. </li>
<li> Reasonable error checking is required, the program must handle the following
events gracefully
<ul>
<li> the specified input file does not exist. </li>
<li> an incorrect number of command line parameters are given. </li>
<li> the file contains invalid records or an invalid record structure. </li>
</ul>
</li>
<li> <a href="#h">Transaction.h</a> header file may be obtained by downloading
the Zip file for assignment 4.</li>
</ul>
<p><a href=".//COMP2301-assignment-4-transaction.exe" title="Downloadable application - Stopwatch">Compiled
(WIN32) binary</a> (188 KB)<br />
<a href="#h">transaction.h</a><br />
<a href="#cpp">transaction.cpp</a></p>
<p>transaction.h<br />
<textarea name="h" cols="82" rows="180" readonly="readonly" title="C++ Header File">/*
*
* Subsystem: TRANSACTION
*
* File Name: transaction.h
*
* Author: Stefan Lehmann
* Modified: Ned Martin 40529927, 18-MAY-2004
*
* Date Created: 07/03/2004
*
* Description: Header file for Transaction class.
*
*/
#ifndef __TRANSACTION_H__
#define __TRANSACTION_H__
class Transaction;
istream& operator >> (istream& ioStream, Transaction& iTransaction);
ostream& operator << (ostream& ioStream, const Transaction& iTransaction);
class Transaction
{
public:
/*
* Name: Transaction()
*
* Purpose: Default Constructor
*
* Method: Initialise data members
*/
Transaction();
/*
* Name: Transaction()
*
* Purpose: Constructor with arguments
*
* Method: Initialise data members with given info
*/
Transaction(long iTimeStamp, char *iCustomerName, long iCustomerRefNum,
char *iAccountType, char *iTransactionType, float iAmount);
/*
* Name: ~Transaction()
*
* Purpose: Destructor
*
* Method: Deallocate memory
*/
~Transaction();
// operators
/*
* Name: operator ==
*
* Purpose: Equality operator
*
* Method: Checks if Transaction is the same.
*/
bool operator== (const Transaction& iRightParameter);
/*
* Name: operator !=
*
* Purpose: Inequality operator
*
* Method: Checks if Transaction is NOT the same.
*/
bool operator!= (const Transaction& iRightParameter);
/*
* Name: operator /=
*
* Purpose: Combined transaction test operator
*
* Method: Checks if Transaction has identical customer ref#
* and account type
*/
bool operator/= (const Transaction& iRightParameter);
/*
* Name: operator <
*
* Purpose: Less than
*
* Method: Checks if Transaction is less than.
*/
bool operator< (const Transaction& iRightParameter);
/*
* Name: operator >
*
* Purpose: Greater than
*
* Method: Checks if Transaction is greater than.
*/
bool operator> (const Transaction& iRightParameter);
/*
* Name: operator =
*
* Purpose: Copy
*
* Method: Ensure a deep copy.
*/
Transaction& operator= (const Transaction& iRightParameter);
/*
* Name: operator +
*
* Purpose: Combine
*
* Method: Combine Transaction with other Transaction
*/
Transaction& operator+ (const Transaction& iRightParameter);
static void Transaction::setSortBy (int iFieldToSortBy)
{
mSortBy = iFieldToSortBy;
}
// Friend functions
/*
* Name: operator >>
*
* Purpose: Input operation
*
* Method: Assume comma separated values, Time Stamp first.
*/
friend istream& operator >> (istream& ioStream,
Transaction& iTransaction);
/*
* Name: operator <<
*
* Purpose: Output operation
*
* Method: Output comma separated values, Time Stamp first.
*/
friend ostream& operator << (ostream& ioStream,
const Transaction& iTransaction);
enum
{
kSORT_BY_TIMESTAMP
};
private:
static int mSortBy;
// Insert Transaction data entries here
// Transaction data entries
long TimeStamp;
char CustomerName[300];
// value exceeds long, changed to char array
char CustomerRefNum[300];
char AccountType[300];
char TransactionType[300];
float Amount;
};
#endif //__TRANSACTION_H__
</textarea>
</p>
<p>transaction.cpp<br />
<textarea name="cpp" cols="82" rows="574" readonly="readonly" title="C++ Code">/*
* Author: Ned Martin #40529927
*
* Creation Date: 18-MAY-2004
*
* Version: FINAL 18-MAY-2004
*
* Copyright: Copyright (c) 2004 Ned Martin, Student s40529927,
* for COMP2301, University of Queensland
*
* Description: Assignment 4 for COMP2301
* Reads an input file, parses file for tokens, reads each
* line into a Transaction, stores Transactions in a list,
* and depending on commandline input, sorts list in a
* variety of ways, or combines specific Transactions,
* then either prints them out to cout or to a specified
* file. May also cause hair loss.
*
* Restrictions: Basic error checking is performed on the input file,
* but generally it is assumed to be in a valid format as
* per the assignment specification.
*
* Usage: [ [/t] | [/n] | [/c] ] INPUTFILE [OUTPUTFILE]
* /t [DEFAULT] : sort transactions in Numeric
* order by Time Stamp
* /n : sort transactions in
* Alphabetic order by Last Name
* /c : sort transactions in Numeric
* order by Time Stamp of combined
*
* Tab Stops: Eight spaces
*/
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#include <iostream> // cout, cerr, shift operators
#include <fstream> // file streams
#include <list> // list, iterator
#include <string> // strlen, string functions
#include <iomanip> // setw, setfill, setprecision
using namespace std;
#include "transaction.h"
bool combine; // flag specifying when we are combining transactions
// set mSortBy to 0 so we sort by Numeric Order of Timestampe by default
int Transaction::mSortBy = 0;
/*
* Function: stripSpace
*
* Purpose: Strips leading spaces from a string.
*
* Method: Accepts pointer to char string and returns pointer to first
* non-space character in string pointed to.
*
* Returns: char pointer to stripped string.
*/
char* stripSpace
(
char* temp // pointer to string
)
{
int ii; // counter
char *p; // holds temporary string
p = temp;
for (ii = 0; ii < strlen (temp); ii++)
{
// first non-space char is found so exit loop
if (!isspace (temp[ii]))
{
break;
}
}
p += ii;
strcpy (temp, p);
return temp;
} // end stripSpace
/*
* Name: Transaction()
*
* Purpose: Default Constructor
*
* Method: Initialise data members
*
* Note: There is nothing to do here.
*/
Transaction::Transaction()
{
// There is nothing to initialise
}
/*
* Name: ~Transaction()
*
* Purpose: Destructor
*
* Method: Deallocate memory
*
* Note: There is nothing to do here.
*/
Transaction::~Transaction()
{
// There is nothing to destroy.
}
// begin redefining operators
/*
* Name: operator /=
*
* Purpose: Combined transaction test operator
*
* Method: Checks if Transaction has identical customer ref#
* and account type
*/
bool Transaction::operator/=
(
const Transaction& iRightParameter // right hand operand
)
{
// return true when customer ref num and account type of both
// transactions are equal
return (!(strcmp (CustomerRefNum, iRightParameter.CustomerRefNum))
&& !(strcmp (AccountType, iRightParameter.AccountType)));
} // end operator/=
/*
* Name: operator <
*
* Purpose: Less than
*
* Method: Checks if Transaction is less than.
*/
bool Transaction::operator<
(
const Transaction& iRightParameter // right hand operand
)
{
// sorting by customer name
if( mSortBy )
{
return (strcmp (CustomerName, iRightParameter.CustomerName)
== -1);
}
// sorting by timestamp
else
{
return (TimeStamp < iRightParameter.TimeStamp);
}
} // end operator<
/*
* Name: operator >
*
* Purpose: Greater than
*
* Method: Checks if Transaction is greater than.
*
* Note: This is not currently used.
*/
bool Transaction::operator>
(
const Transaction& iRightParameter // right hand operand
)
{
// sorting by customer name
if( mSortBy )
{
return (strcmp (CustomerName, iRightParameter.CustomerName)
== 1);
}
// sorting by timestamp
else
{
return (TimeStamp > iRightParameter.TimeStamp);
}
} // end operator>
/*
* Name: operator +
*
* Purpose: Combine
*
* Method: Combine Transaction with other Transaction
*/
Transaction& Transaction::operator+
(
const Transaction& iRightParameter // right hand operand
)
{
float amount = 0; // holds temporary amount
// set timestamp to new timestamp only if new timestamp is newer
if( iRightParameter.TimeStamp > TimeStamp )
{
TimeStamp = iRightParameter.TimeStamp;
}
// set type of transaction to "CombDep"
strcpy (TransactionType, "CombDep");
// sum amounts
// negative amount if transaction type is withdrawal
if( strcmp (iRightParameter.TransactionType, "With") == 0 )
{
amount -= iRightParameter.Amount;
}
// positive amount if transaction is deposit
else
{
amount += iRightParameter.Amount;
}
// negative amount if transaction type is withdrawal
if( strcmp (TransactionType, "With") == 0 )
{
amount -= Amount;
}
// positive amount if transaction is deposit
else
{
amount += Amount;
}
Amount = amount;
return *this;
} // end operator+
/*
* Name: operator >>
*
* Purpose: Input operation
*
* Method: Assume comma separated values, Time Stamp first.
*/
istream& operator >>
(
istream& ioStream, // input ioStream
Transaction& iTransaction // output Transaction
)
{
char tempString[300]; // temporary array
char delim = ','; // deliminator
// tokenise on deliminators
// long
ioStream.getline (tempString, 256, delim);
stripSpace(tempString);
iTransaction.TimeStamp = atol (tempString);
// invalid timestamp
if( !(iTransaction.TimeStamp > 0) )
{
cerr << "Invalid Input Detected" << endl;
exit (EXIT_FAILURE);
}
//char[]
ioStream.getline (tempString, 256, delim);
stripSpace(tempString);
strcpy (iTransaction.CustomerName, tempString);
// long
ioStream.getline (tempString, 256, delim);
stripSpace(tempString);
strcpy (iTransaction.CustomerRefNum, tempString);
// char[]
ioStream.getline (tempString, 256, delim);
stripSpace(tempString);
strcpy (iTransaction.AccountType, tempString);
// char[]
ioStream.getline (tempString, 256, delim);
stripSpace(tempString);
strcpy (iTransaction.TransactionType, tempString);
// float
// read to end of line
ioStream.getline (tempString, 256);
stripSpace(tempString);
iTransaction.Amount = atof (tempString);
return ioStream;
} // end operator >>
/*
* Name: operator <<
*
* Purpose: Output operation
*
* Method: Output comma separated values, Time Stamp first.
*/
ostream& operator <<
(
ostream& ioStream, // output ioStream
const Transaction& iTransaction // input Transaction
)
{
// long
// set width to 10 and fill with 0's
ioStream << setw (10) << setfill ('0')
<< iTransaction.TimeStamp << ", ";
// char*
ioStream << iTransaction.CustomerName << ", ";
// long
ioStream << iTransaction.CustomerRefNum << ", ";
// char*
ioStream << iTransaction.AccountType << ", ";
// char*
ioStream << iTransaction.TransactionType << ", ";
// float
// set precision to 2 and fixed notation
ioStream << setprecision (2) << fixed << iTransaction.Amount << endl;
return ioStream;
} // end operator <<
// end operators
/*
* Function: checkSwitch
*
* Purpose: Checks commandline input for valid switches.
*
* Method: Accepts array of characters and tests to see if it contains
* valid switches. Sets bool combine to true if switch was 'c',
* sets mSortBy to 1 if switch was 'n'.
*
* Returns: true if valid switch was encountered.
false otherwise.
*/
bool checkSwitch
(
char args[] // array containing possible switch
)
{
// check if it is a valid argument beginning with '/' or '-'
switch( args[0] )
{
case '/':
case '-':
break;
default :
return false;
}
// check that the second char is a valid char, 't', 'n' or 'c'
switch( args[1] )
{
// sort transactions in Numeric order by Time Stamp
case 't':
//Transaction::setSortBy ( 0 ) is already set
// dont need to do anything here
break;
// sort transactions in Alphabetic order by Last Name
case 'n':
Transaction::setSortBy ( 1 );
break;
// sort transactions in Numeric order by Time Stamp of combined
// deposit balance
case 'c':
combine = true;
break;
// is not valid switch
default :
return false;
break;
}
// is a valid switch
return true;
} // end checkSwitch
/*
* Function: main
*
* Purpose: Does heaps of things, causes headaches and hair loss.
*
* Method: Parses commandline input, creates Transactions from an input
* file, adds them to list, sorts this list, possibly combines
* transactions, and prints them out to cout or a file.
*
* Returns: EXIT_SUCCESS on success
*/
int main
(
int argc,
char *argv[]
)
{
ofstream outputFile; // Output file
ifstream inputFile; // Input file
bool printToFile = false; // file printing flag
list<Transaction> transactions; // list to hold Transactions
list<Transaction>::iterator transactionsIterator; // iterator over list
// create a new Transaction
Transaction *transaction = new Transaction();
// parse commandline arguments
switch( argc - 1 )
{
// switch, inputfile, outputfile
case 3:
// check switch
checkSwitch(argv[1]);
// open files
inputFile.open (argv[2]);
outputFile.open (argv[3]);
break;
// input file, output file OR switch, input file
case 2:
// if 1 is switch then 2 is input file
if( checkSwitch(argv[1]) )
{
// 2 is input file
inputFile.open (argv[2]);
}
// else 1 is input and 2 is output
else
{
inputFile.open (argv[1]);
outputFile.open (argv[2]);
}
break;
// input file
case 1:
// open file
inputFile.open (argv[1]);
break;
// is an error so print error msg and exit
default :
cerr << "Usage: " << argv[0] << " ";
cerr << "[ [/t] | [/n] | [/c] ] INPUTFILE [OUTPUTFILE]\n";
cerr << "/t [DEFAULT]\t: sort transactions in Numeric order by "
<< "Time Stamp\n";
cerr << "/n\t\t: sort transactions in Alphabetic order by Last "
<< "Name\n";
cerr << "/c\t\t: sort transactions in Numeric order by Time "
<< "Stamp of combined deposit balance" << endl;
exit (EXIT_FAILURE);
break;
}
// input file is bad so print error and exit
if( !inputFile.good() )
{
cerr << "Invalid Input File" << endl;
exit (EXIT_FAILURE);
}
// output file is open so we are printing to output file
if( outputFile.is_open() )
{
printToFile = true;
}
// for each line in the input file
while( !inputFile.eof() )
{
// parse input stream into transaction
inputFile >> *transaction;
// add Transaction to list
transactions.push_back(*transaction);
}
// sort list of transactions depending on mSortBy flag
transactions.sort();
/*
Combine transactions
assume transactions are sorted by cust ref
for all ii
for all jj where jj = ii + 1
if transaction[ii] /= transaction[jj]
then combine transactions by
transaction[ii] = transaction[ii] + transaction[jj]
remove transaction[jj] from list
*/
if( combine )
{
// create iterators over the list of Transactions
list<Transaction>::iterator ii;
list<Transaction>::iterator jj;
for (ii = transactions.begin(); ii != transactions.end(); ii++)
{
for (jj = ii; jj != transactions.end(); jj++)
{
if( (ii != jj) && (*ii /= *jj) )
{
*ii + *jj;
if (jj != transactions.end())
{
transactions.erase(jj++);
}
}
}
}
}
// print list of transactions
for (transactionsIterator = transactions.begin();
transactionsIterator != transactions.end();
transactionsIterator++)
{
// print to file
if( printToFile )
{
outputFile << *transactionsIterator;
}
// print to cout
else
{
cout << *transactionsIterator;
}
}
// close files
outputFile.close();
inputFile.close();
// destroy transaction
delete transaction;
return EXIT_SUCCESS;
} // end main
</textarea>
<br />
Code © Copyright 2004 Ned Martin</p>
<p>19-May-2004</p>
</body>
</html>