I've searched high and low trying to debug this, but so far I can't figure it out.
I've got a class declaration in a file named DataList.h, the methods in a file named DataList.cc file, and the main program in a separate .cc file.
DataList.cc has an #include header to include DataList.h.
whenever I run
g++ DataList.cc
in Ubuntu terminal, it spits out
DataList.cc: In function ‘bool TransactOnce(int&, TRANS&, std::string&)’:
DataList.cc:395:2: error: ‘ListNodeT’ was not declared in this scope
DataList.cc:395:13: error: ‘nodeTPtr’ was not declared in this scope
DataList.cc:396:13: error: ‘headTrans’ was not declared in this scope
What's weird is that I declare variables of these type ALL OVER THE PLACE in my other member functions in DataList.cc, but the compiler doesn't give me any other errors besides those above. I'm trying to figure out what it is that g++ doesn't like about those particular declarations in that one function.
'ListNodeT' is a struct within my main class, and the struct includes a pointer to another object that struct type. 'nodeTPtr' is simply a pointer to a 'ListNodeT' object, and 'headTrans' is a pointer (contained privately in the class) that points to an object of type ListNodeT, particularly, the very first node in the linked list.
The class "List" is intended for linked lists.
Here's the "DataList.h" file:
#ifndef DATALIST_H
#define DATALIST_H
#include <iostream>
#include <fstream>
#include <ostream>
#include <iomanip>
using namespace std;
const int MAXDISCIPLINES = 4;
const int MAXBREEDS = 4;
struct HORSE {
int ID;
string name; // maximum 25 alphanumeric characters, spaces included
double height;// in inches?
int age;
char genderCode;//'m', 'f', 'M', or 'F'
int breed;
int disciplineCount;
int discipline[MAXDISCIPLINES];
double lowBid; // minimum selling price
};
struct TRANS {
char transCode; //'A' for add, 'D' for delete or updating disciplines, or 'P' for updating lowBid price
HORSE transHorse;
};
class List {
private:
struct ListNodeT {
TRANS trans;
struct ListNodeT *nextLNT;
};
ListNodeT *headTrans;
struct ListNodeH {
HORSE horse;
struct ListNodeH *nextLNH;
};
ListNodeH *headHorse;
public:
//ListNodeH *headHorse;
//ListNodeT *headTrans;
List();
List(const List &obj);
~List();
bool InsertHorse(HORSE newHorse);
bool InsertTrans(TRANS newTrans);
bool DeleteHorse(int target);
bool DeleteTrans(int target);
bool ViewHorse(int target, HORSE &viewHorse);
bool ViewTrans(int target, TRANS &viewTrans);
int getNumHorses();
void getNumTrans(int &numA, int &numDel, int &numDisc, int &numP);
bool TransactOnce(int &skip, TRANS &thisTrans, string &failString);
bool UpdateDisc(TRANS thisTrans);
bool UpdatePrice(TRANS thisTrans);
void ReportOneTransaction(fstream &strm, TRANS thisTrans);
}; //end List class definition
//methods are in file DataList.cc and compiled separately.
#endif
And below is my "DataList.cc" file. The problematic "TransactOnce()" is towards the bottom.
#include "DataList.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <ostream>
#include <iomanip>
using namespace std;
//constructor
List::List(){
headHorse = NULL;
headTrans = NULL;
}
//copy constructor
List::List(const List &obj){
//copy the linked list of horses
ListNodeH *nodeHPtr;
ListNodeH **newListHPtr;
headHorse = NULL;
newListHPtr = &headHorse; //means &(this->headHorse), not &(obj.headHorse)
nodeHPtr = obj.headHorse;
while (nodeHPtr != NULL) {
*newListHPtr = new ListNodeH;
(*newListHPtr)->horse = nodeHPtr->horse;
(*newListHPtr)->nextLNH = NULL;
newListHPtr = &((*newListHPtr)->nextLNH);
nodeHPtr = nodeHPtr->nextLNH;
}
//copy the linked list of transactions
ListNodeT *nodeTPtr;
ListNodeT **newListTPtr;
headTrans = NULL;
newListTPtr = &headTrans;
nodeTPtr = obj.headTrans;
while (nodeTPtr != NULL) {
*newListTPtr = new ListNodeT;
(*newListTPtr)->trans = nodeTPtr->trans;
(*newListTPtr)->nextLNT = NULL;
newListTPtr = &((*newListTPtr)->nextLNT);
nodeTPtr = nodeTPtr->nextLNT;
}
}//end copy constructor
//destructor
List::~List(){
//destroy the list of horses
ListNodeH *nodeHPtr;
ListNodeH *nextHNode;
nodeHPtr = headHorse;
while(nodeHPtr != NULL){
nextHNode = nodeHPtr->nextLNH;
delete nodeHPtr;
nodeHPtr = nextHNode;
}//end walkthrough
//destroy the list of transactions
ListNodeT *nodeTPtr;
ListNodeT *nextTNode;
nodeTPtr = headTrans;
while(nodeTPtr != NULL){
nextTNode = nodeTPtr->nextLNT;
delete nodeTPtr;
nodeTPtr = nextTNode;
}//end walkthrough
}//end List::~List()
//********************************************************************
// FUNCTION NAME: InsertHorse()
// FUNCTION PURPOSE: inserts a new HORSE struct into our list
// INPUT PARAMETERS:
// 1. HORSE newHorse - the object of type DATA to be inserted into the List.
//RETURN VALUE – bool
//********************************************************************
bool List::InsertHorse(HORSE newHorse){
bool success = false;
ListNodeH *newNodeHPtr;
ListNodeH *nodeHPtr;
ListNodeH *prevNodeHPtr = NULL;
newNodeHPtr = new ListNodeH;
newNodeHPtr->horse = newHorse;
if(!headHorse){ //if head==NULL, our list is empty
headHorse = newNodeHPtr;
newNodeHPtr->nextLNH = NULL;
success = true;
}
else { //perhaps add? Our list is currently not empty.
nodeHPtr = headHorse;
//prevNodePtr; [sic] in my notes. I think it's supposed to be prevNodePtr = NULL;, but this should already be true
while(nodeHPtr != NULL && nodeHPtr->horse.ID < newHorse.ID){ //searches for approriate place
prevNodeHPtr = nodeHPtr;
nodeHPtr = nodeHPtr->nextLNH;
}
if(nodeHPtr != NULL && nodeHPtr->horse.ID == newHorse.ID){ //checks for duplicates
delete newNodeHPtr;
success = false; //note: this is the only way that Insert could return false
}
else { //insert the node
success = true;
newNodeHPtr->nextLNH = nodeHPtr;
if(prevNodeHPtr == NULL) //we're at the beginning of the list
headHorse = newNodeHPtr;
else //not at the beginning of the list
prevNodeHPtr->nextLNH = newNodeHPtr;
}//successful insertion
}
// delete newNodeHPtr;
return success;
}
//end List::InsertHorse()
//********************************************************************
// FUNCTION NAME: InsertTrans()
// FUNCTION PURPOSE: inserts a new TRANS struct into our list.
// if the transaction is trying to delete or update a horse that does not exist,
// returns false, and transaction is not inserted.
// INPUT PARAMETERS:
// 1. TRANS newTrans - the object of type TRANS to be inserted into the List.
//RETURN VALUE – bool
//********************************************************************
bool List::InsertTrans(TRANS newTrans){
bool success = false;
ListNodeT *newNodeTPtr;
ListNodeT *nodeTPtr;
ListNodeT *prevNodeTPtr = NULL;
newNodeTPtr = new ListNodeT;
newNodeTPtr->trans = newTrans;
HORSE dummyHorse; //dummy variable to be passed by reference to ViewHorse()
//we need to ensure a few things
//no duplicate IDs in transactions
//no Del, Disc, or P transactions for which the horse dosn't already exist in inventory
if(!headTrans){ //if head==NULL, our list is empty
headTrans = newNodeTPtr;
newNodeTPtr->nextLNT = NULL;
success = true;
}
else { //perhaps add? Our list is currently not empty.
nodeTPtr = headTrans;
//prevNodePtr; [sic] in my notes. I think it's supposed to be prevNodePtr = NULL;, but this should already be true
while(nodeTPtr != NULL && nodeTPtr->trans.transHorse.ID < newTrans.transHorse.ID){ //searches for approriate place
prevNodeTPtr = nodeTPtr;
nodeTPtr = nodeTPtr->nextLNT;
}
//check for duplicates
if(nodeTPtr != NULL && nodeTPtr->trans.transHorse.ID == newTrans.transHorse.ID){
delete newNodeTPtr;
success = false;
}
//in the case of Delete or Update transactions for which the horse does not already exist in inventory
else if((newTrans.transCode == 'D' || newTrans.transCode == 'P') && !List::ViewHorse(newTrans.transHorse.ID, dummyHorse)){
delete newNodeTPtr;
success = false;
}
else { //insert the transaction node
success = true;
newNodeTPtr->nextLNT = nodeTPtr;
if(prevNodeTPtr == NULL) //we're at the beginning of the list
headTrans = newNodeTPtr;
else //not at the beginning of the list
prevNodeTPtr->nextLNT = newNodeTPtr;
}//successful insertion
}
// delete newNodeTPtr;
return success;
}//end List::InsertTrans()
//********************************************************************
// FUNCTION NAME: DeleteHorse()
// FUNCTION PURPOSE: deletes a HORSE struct from our object of class List.
// INPUT PARAMETERS:
// 1. int target - the ID of the object of type HORSE to be deleted from List
//RETURN VALUE – bool
//********************************************************************
bool List::DeleteHorse(int target){
bool success = false;
ListNodeH *nodeHPtr;
ListNodeH *prevHPtr;
if (!headHorse) //empty list
success = false;
else if (headHorse->horse.ID == target) { //found target at the beginning of list, delete it
nodeHPtr = headHorse->nextLNH;
delete headHorse;
headHorse = nodeHPtr;
success=true;
}
else { // maybe delete?
nodeHPtr = headHorse;
while(nodeHPtr!=NULL && nodeHPtr->horse.ID < target){ //searching...
prevHPtr = nodeHPtr;
nodeHPtr = nodeHPtr->nextLNH;
}
if(nodeHPtr == NULL && nodeHPtr->horse.ID != target) //we're at the end of the list, and if target's not here...
success=false; //deletion failed. This is the only case where Delete() returns false.
else { //we're between the beginning and end, and we found the target
prevHPtr->nextLNH = nodeHPtr->nextLNH;
delete nodeHPtr; //delete target.
success = true;
}
}
return success;
}
//********************************************************************
// FUNCTION NAME: DeleteTrans()
// FUNCTION PURPOSE: deletes a TRANS struct from our object of class List.
// INPUT PARAMETERS:
// 1. int target - the ID of the object of type TRANS to be deleted from List
//RETURN VALUE – bool
//********************************************************************
bool List::DeleteTrans(int target){
bool success = false;
ListNodeT *nodeTPtr;
ListNodeT *prevTPtr;
if (!headTrans) //empty list
success = false;
else if (headTrans->trans.transHorse.ID == target) { //found target at the beginning of list, delete it
nodeTPtr = headTrans->nextLNT;
delete headTrans;
headTrans = nodeTPtr;
success=true;
}
else { // maybe delete?
nodeTPtr = headTrans;
while(nodeTPtr!=NULL && nodeTPtr->trans.transHorse.ID < target){ //searching...
prevTPtr = nodeTPtr;
nodeTPtr = nodeTPtr->nextLNT;
}
if(nodeTPtr == NULL && nodeTPtr->trans.transHorse.ID != target) //we're at the end of the list, and if target's not here...
success=false; //deletion failed. This is the only case where Delete() returns false.
else { //we're between the beginning and end, and we found the target
prevTPtr->nextLNT = nodeTPtr->nextLNT;
delete nodeTPtr; //delete target.
success = true;
}
}
return success;
}
//********************************************************************
// FUNCTION NAME: ViewHorse()
// FUNCTION PURPOSE: finds the HORSE struct whose ID is target, then returns the HORSE by reference.
// INPUT PARAMETERS:
// 1. int target - the ID to be searched for
// 2. HORSE &viewHorse - the object of type HORSE to be found and returned (by reference)
//RETURN VALUE – bool
//********************************************************************
//returns by reference the HORSE in the list with ID == target
//if View() returns false, then the target was not found and &viewHorse was not changed by ViewHorse().
bool List::ViewHorse(int target, HORSE &viewHorse){
bool success = false;
ListNodeH *nodeHPtr;
nodeHPtr = headHorse; //start at the beginning of the list
while(nodeHPtr != NULL && nodeHPtr->horse.ID < target) //search...
nodeHPtr = nodeHPtr->nextLNH;
//which test failed?
if(nodeHPtr == NULL || nodeHPtr->horse.ID != target) //we're at the end of the list, or didn't find the target.
success = false; //Note: this is the ONLY way that ViewHorse() returns false.
else { //nodeHPtr != NULL && nodeHPtr->horse.ID == target, we found the target
success = true;
viewHorse = nodeHPtr->horse; //return by reference the HORSE in the list with ID == target
}
return success;
}//end List::ViewHorse()
//********************************************************************
// FUNCTION NAME: ViewTrans()
// FUNCTION PURPOSE: finds the TRANS struct whose ID is target, then returns the TRANS by reference.
// INPUT PARAMETERS:
// 1. int target - the ID to be searched for
// 2. TRANS &viewTrans - the object of type TRANS to be found and returned (by reference)
//RETURN VALUE – bool
//********************************************************************
//returns by reference the TRANS in the list with ID == target
//if ViewTrans() returns false, then the target was not found and &viewTrans was not changed by ViewTrans().
bool List::ViewTrans(int target, TRANS &viewTrans){
bool success = false;
ListNodeT *nodeTPtr;
nodeTPtr = headTrans; //start at the beginning of the list
while(nodeTPtr != NULL && nodeTPtr->trans.transHorse.ID < target) //search...
nodeTPtr = nodeTPtr->nextLNT;
//which test failed?
if(nodeTPtr == NULL || nodeTPtr->trans.transHorse.ID != target) //we're at the end of the list, or didn't find the target.
success = false; //Note: this is the ONLY way that ViewTrans() returns false.
else { //nodeTPtr != NULL && nodeTPtr->horse.ID == target, we found the target
success = true;
viewTrans = nodeTPtr->trans; //return by reference the TRANS in the list with ID == target
}
return success;
}//end List::ViewTrans
//********************************************************************
// FUNCTION NAME: getNumHorses()
// FUNCTION PURPOSE: returns the number of nodes in our list of horses
// INPUT PARAMETERS: [none]
//RETURN VALUE – int
//********************************************************************
int List::getNumHorses(){
int horseCounter = 0;
ListNodeH *nodeHPtr;
nodeHPtr = headHorse;
while(nodeHPtr != NULL){
nodeHPtr = nodeHPtr->nextLNH;
horseCounter++;
}
return horseCounter;
}//end List::getNumHorses()
//********************************************************************
// FUNCTION NAME: getNumTrans()
// FUNCTION PURPOSE: returns (by reference) the numbers of various types of transactions in our list of transactions
// INPUT PARAMETERS:
// 1.int &numA - number of "Add" transactions
// 2.int &numDel - number of "Delete" transactions
// 3.int &numDisc - number of "update discipline" transactions
// 4.int &numP - number of "update lowBid" transactions
//RETURN VALUE – void
//********************************************************************
void List::getNumTrans(int &numA, int &numDel, int &numDisc, int &numP){
numA = 0;
numDel = 0;
numDisc = 0;
numP = 0;
ListNodeT *nodeTPtr;
nodeTPtr = headTrans;
while(nodeTPtr != NULL){
if(nodeTPtr->trans.transCode == 'A')
numA++;
else if(nodeTPtr->trans.transCode == 'D'){
if (nodeTPtr->trans.transHorse.disciplineCount == 0)
numDel++;
else
numDisc++;
}
else if(nodeTPtr->trans.transCode == 'P'){
numP++;
}
nodeTPtr = nodeTPtr->nextLNT;
}
}//end List::getNumTrans()
//********************************************************************
// FUNCTION NAME: TransactOnce()
// FUNCTION PURPOSE: Performs a single transaction.
// [skip] number of transactions at the beginning of the linked list of trans are skipped.
// The transaction immediately after the skipped transactions is attempted.
// If the transaction fails, skip is incremented and the function returns false.
// In any case, thisTrans is returned by reference as the transaction that was just attempted.
// INPUT PARAMETERS:
// 1. int &skip - the number of transactions to skip
// 2. TRANS &thisTrans - the returned transaction that was just attempted
// 3. string &failString - the ERROR, if any.
//RETURN VALUE – bool
//********************************************************************
bool TransactOnce(int &skip, TRANS &thisTrans, string &failString){
bool success = true;
stringstream failStream;
ListNodeT *nodeTPtr;
nodeTPtr = headTrans;
HORSE dummyHorse; //for ViewHorse()
//if 'A', the ID must not already exist in our list of horses
//if 'D' or 'P', the horse must already exist in our list of horses.
//if 'D' and disciplineCount != 0, then
//the existing horse must already have disciplineCount <4
//transaction's transHorse.discipline[] must not have duplicates in the array
//each of transaction's transHorse.discipline[]s must be valid (1<= discipline <=4)
//find the transaction in question
for (int i=0; i < skip; i++){
nodeTPtr = nodeTPtr->nextLNT;
}
//nodeTPtr is now pointing to the appropriate ListNodeT.
if (nodeTPtr->trans.transCode == 'A' && !List::InsertHorse(nodeTPtr->trans.transHorse)){
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via InsertHorse().";
success = false;
}
else if (nodeTPtr->trans.transCode == 'D'){ //delete or update disciplines
if(nodeTPtr->trans.transHorse.disciplineCount == 0 && !List::DeleteHorse(nodeTPtr->trans.transHorse.ID)){ //for deletion
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via DeleteHorse().";
success = false;
}
else if(nodeTPtr->trans.transHorse.disciplineCount != 0 && !List::UpdateDisc(nodeTPtr->trans)){ //update disciplines
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via UpdateDisc().";
success = false;
}
}
else if (nodeTPtr->trans.transCode == 'P' && !List::UpdatePrice(nodeTPtr->trans)){
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << " via UpdatePrice().";
success = false;
}
else {
failStream << "ERROR for horse transaction" << nodeTPtr->trans.transHorse.ID << ", not a valid transCode.";
success = false;
}
if (success){ //attempt to delete the transaction
if (!List::DeleteTrans(nodeTPtr->trans.transHorse.ID)){
failStream << "ERROR, could not delete transaction " << nodeTPtr->trans.transHorse.ID << ".";
success = false;
}
else //return true and error free
failStream << "No error to report.";
}
if (!success)
skip++;
failStream << "\n";
failString = failStream.str();
return success;
}//end TransactOnce()
//********************************************************************
// FUNCTION NAME: UpdateDisc()
// FUNCTION PURPOSE: for an "update discipline" transaction, update the disciplines of that horse in inventory.
// INPUT PARAMETERS:
// 1. TRANS thisTrans - the transaction to be executed
//RETURN VALUE – bool
//********************************************************************
bool List::UpdateDisc(TRANS thisTrans){
bool success = true;
ListNodeH *nodeHPtr = headHorse; //no need for a ListNodeT
//obtain a pointer to the horse in question
while (nodeHPtr != NULL && nodeHPtr->horse.ID < thisTrans.transHorse.ID)
nodeHPtr = nodeHPtr->nextLNH;
if(nodeHPtr == NULL) //failed to find the horse
success = false;
//horse found; nodeHPtr->horse.ID == thisTrans.transHorse.ID
else if(thisTrans.transCode != 'D') //this isn't even a "D" transaction...
success = false;
else if(thisTrans.transHorse.disciplineCount == 0) //nothing to do, this is for deletion
success = false;
else if(nodeHPtr->horse.disciplineCount + thisTrans.transHorse.disciplineCount > 4)
success = false; //too many disciplines
else {
//update the disciplines
while(thisTrans.transHorse.disciplineCount !=0){
nodeHPtr->horse.discipline[nodeHPtr->horse.disciplineCount] = thisTrans.transHorse.discipline[thisTrans.transHorse.disciplineCount-1];
nodeHPtr->horse.disciplineCount++;
thisTrans.transHorse.disciplineCount--;
}//disciplines are now updated but perhaps not sorted
//bubble-sort the horse's array of disciplines.
int i, j;
bool swaped = true;
int tempInt;
for(i = 1; (i <= nodeHPtr->horse.disciplineCount)&&swaped; i++){
swaped = false;
for (j=0; j< nodeHPtr->horse.disciplineCount-1; j++){
if(nodeHPtr->horse.discipline[j] > nodeHPtr->horse.discipline[j+1]){
tempInt = nodeHPtr->horse.discipline[j];
nodeHPtr->horse.discipline[j] = nodeHPtr->horse.discipline[j+1];
nodeHPtr->horse.discipline[j+1] = tempInt;
swaped = true;
}
}
}
}//end update and sort horse's disciplines
return success;
}//end List::UpdateDisc()
//********************************************************************
// FUNCTION NAME: UpdatePrice()
// FUNCTION PURPOSE: for an "update lowBid" transaction, update the lowBid of that horse in inventory.
// INPUT PARAMETERS:
// 1. TRANS thisTrans - the transaction to be executed
//RETURN VALUE – bool
//********************************************************************
bool List::UpdatePrice(TRANS thisTrans){
bool success = true;
ListNodeH *nodeHPtr;
nodeHPtr = headHorse;
//obtain a pointer to the horse in question
while (nodeHPtr != NULL && nodeHPtr->horse.ID < thisTrans.transHorse.ID)
nodeHPtr = nodeHPtr->nextLNH;
if(nodeHPtr == NULL) //failed to find the horse
success = false;
//else, horse found; nodeHPtr->horse.ID == thisTrans.transHorse.ID
else if(thisTrans.transCode != 'P') //this isn't even a "P" transaction...
success = false;
else { //update lowBid
nodeHPtr->horse.lowBid = thisTrans.transHorse.lowBid;
}
return success;
}//end List::UpdatePrice()
//********************************************************************
// FUNCTION NAME: ReportOneTransaction()
// FUNCTION PURPOSE: prints to Report.out a single transaction. called by Transact().
// INPUT PARAMETERS:
// 1. fstream &strm - the stream to print to.
// 2. TRANS oneTrans - the transaction being reported.
//RETURN VALUE – void
//********************************************************************
void List::ReportOneTransaction(fstream &strm, TRANS oneTrans){
//some "Ragged Arrays"
string breedDescription[MAXBREEDS+1] = {"Dummy", "Pleasure Saddle Horse", "American Fox Trotter", "Virginia Highlander", "Arabian"};//21
string disciplineDescription[MAXDISCIPLINES+1] = {"Dummy", "Dressage", "Jumper", "Hunter", "Western Pleasure"};//16
if (oneTrans.transCode == 'A')
strm << "Horse ADDED to inventory named '" ;
else
strm << "Horse REMOVED from inventory named '" ;
strm << oneTrans.transHorse.name << "'"<< endl;
strm << "______________________________________________________________________\n";//70
strm <<"ID Height Age M/F LowBid "<< oneTrans.transHorse.disciplineCount << " Discipline(s): Breed\n";
strm << left << setw(3) <<oneTrans.transHorse.ID <<" ";//ID
strm << left << setw(5) <<setprecision(2) <<oneTrans.transHorse.height <<" ";//height (double)
strm << left << setw(3) <<oneTrans.transHorse.age <<" ";//age
strm << left << setw(1) <<oneTrans.transHorse.genderCode; //genderCode (char)
strm << " "<<left<<'$';
strm << right << fixed << setw(8) << setprecision(2) << oneTrans.transHorse.lowBid ;//lowBid (double)
strm << left << " " << setw(16) << disciplineDescription[oneTrans.transHorse.discipline[0]] ;
strm << " " << breedDescription[oneTrans.transHorse.breed] << endl;
for (int j=1; j < oneTrans.transHorse.disciplineCount; j++){
strm << " ";
strm << disciplineDescription[oneTrans.transHorse.discipline[j]] << endl;
}
strm << endl << endl;
}//end ReportOneTransaction()