Reputation: 35
New CS Student in need of direction/help. I trying to sort my pRecordBook Array by the class member picked on user end. But for some reason when executing my comparison is just voided or not taken.
clang 11.0.3 Xcode
#include <iostream>
#include <fstream>
#include <string>
const int MAX_RECORDS = 200;
class Record{ // Record Class with members
private:
std::string id;
std::string name;
int quantity;
double price;
public:
Record();
const std::string getID();
const std::string getName();
const double getPrice();
const int getQuantity();
void setID(std::string num);
void setName(std::string input);
void setQuantity(int quantity);
void setPrice(double price);
void setRecord(std::string id, std::string name, int quantity, double price);
std::string displayRecord();
};
void readFile(Record recordBook[], Record *pRecordBook[], std::string file, int &count);
void displayArray(Record recordBook[], const int count);
void displayArray(Record *pRecordBook[], const int count);
void sortArray(Record *pRecordBook[], const int count, int selection);
std::string searchRecord(Record *pRecordBook[], const int count, std::string &input);
std::string searchRecord(Record *pRecordBook[], const int count, std::string &input);
void printReport(Record recordBook[], const int count);
void displayOptions(int &choice);
int main(int argc, const char * argv[]) {
int selection = 0;
int subSelection = 0;
std::string inputID = "";
std::string inputName = "";
int count = 0;
Record recordBook[MAX_RECORDS];
Record *pRecordBook[MAX_RECORDS];
std::string fileName = "testFile.txt";
readFile(recordBook, pRecordBook, fileName, count);
displayOptions(selection);
while(selection != 0){
switch(selection){
case 1:
std::cout << "\nPrinting Unsorted Inventory";
displayArray(recordBook, count);
break;
case 2:
std::cout << "\nSort By\n1. ID\n2. Name\n3. Quantity\n4. Price\nSelection: ";
std::cin >> subSelection;
while(subSelection < 1 || subSelection > 4){
std::cout << "\nPlease a selection from 1-4\nTry Again: ";
std::cin >> subSelection;
}
sortArray(pRecordBook, count, subSelection);
displayArray(pRecordBook, count);
break;
case 3:
std::cout << "\nSearch for item by:\n1. ID\n2. Name\nSelection: ";
std::cin >> subSelection;
if(subSelection > 2 || subSelection < 1){
std::cout << "\nPlease a selection of 1 or 2\nTry Again: ";
std::cin >> subSelection;
}else{
if(subSelection == 1){
std::cout << "\nEnter ID to search for: ";
std::cin >> inputID;
searchRecord(pRecordBook, count, inputID);
}else{
std::cout << "\nEnter the Name to search for: ";
std::cin >> inputName;
searchRecord(pRecordBook, count, inputName);
}
}
break;
case 4:
printReport(recordBook, count);
break;
default:
std::cout << "\nInvalid Option, Try Again\n";
break;
}
displayOptions(selection);
}
if(selection == 0){
std::cout << "\nTerminated Program. Goodbye\n";
}
return 0;
}
// Get Functions
const std::string Record::getID(){ return id;}
const std::string Record::getName(){ return name;}
const double Record::getPrice(){ return price;}
const int Record::getQuantity(){ return quantity;}
// Set Functions
void Record::setID(std::string num){
this->id = num;
}
void Record::setName(std::string input){
std::string name;
for(char letter: input){
name += toupper(letter);
}
this->name = name;
}
void Record::setQuantity(int quantity){
this->quantity = quantity;
}
void Record::setPrice(double price){
this->price = price;
}
// Contsructor for the initialization of "recordBook Array"
Record::Record(){
id = "";
name = "";
quantity = NULL;
price = NULL;
}
// Function to set the Entire class at once - Called in readFile function
void Record::setRecord(std::string id, std::string name, int quantity, double price){
setID(id);
setName(name);
setQuantity(quantity);
setPrice(price);
}
// Reads file, checks if correct file, checks if its empty, grabs values and stores them in class Record on the recordBook array
void readFile(Record recordBook[], Record *pRecordBook[], std::string fileName, int &count){
std::ifstream inFile;
std::ofstream outFile;
inFile.open(fileName, std::ios::in);
outFile.open("errorFile.txt", std::ios::out | std::ios::app);
while(!inFile){
std::cout << "\nError: Could Not Open File\nTry Again: ";
std::cin >> fileName;
inFile.open(fileName, std::ios::in);
}
while(inFile.peek() == EOF){// Checking if file is empty
std::cout << "\nError: File is Empty\nTry Again: ";
std::cin >> fileName;
inFile.open(fileName, std::ios::in);
}
std::string id;
std::string name;
int quantity;
double price;
while(inFile >> id >> name >> quantity >> price && !(inFile.eof())){
if(price == 0 || quantity == 0){
outFile << id << " " << name << " " << quantity << " " << price << "\n";
}else{
recordBook[count].setRecord(id, name, quantity, price);
pRecordBook[count] = &recordBook[count];
count++;
}
if(count == MAX_RECORDS){
std::cout << "\nProgram Storage Full. Stopping on line " << MAX_RECORDS << "\nUsing values grabbed. . . ";
break;
}
};
outFile.close();
inFile.close();
}
std::string Record::displayRecord(){ // Function to display individual Record
return this->id + " " + this->name + " " + std::to_string(this->quantity) + " " + std::to_string(this->price);
}
void displayArray(Record recordBook[], const int count){ // Function to display all Records in RecordArray
for(int i = 0; i < count; i++){
std::cout << "\nItem: " << (i+1) << " " << recordBook[i].displayRecord();
}
std::cout << "\n";
}
void displayArray(Record *pRecordBook[], const int count){ // Function display all Record in PointerArray
for(int i = 0; i < count; i++){
std::cout << "\n" << pRecordBook[i]->displayRecord();
}
std::cout << "\n";
}
I've worked backwards and even plugged in my regular array, chose one condition, hard coded it in the if statement. - Boom Works
I've then included the switch statement because I had thought the break; in the switch was causing me to get kicked out of my nested loops killing the function in doing so. - Nope works
It's when I have the Pointers Array plugged in that the comparison fails. Is there a cast I am missing or?
// Function to sort array depending on user selection
void sortArray(Record *pRecordBook[], const int count, int selection){
bool toSwap;
bool condition;
Record *pTemp;
for(int i = 0; i < count; i++){
toSwap = false;
for(int j = i + 1; j < count-i-1; j++){
// Seems like our problem is the sorting is not being saved
// Possibly grabbing the data incorrectly or might be the sorting itself that is wrong
switch(selection){
case 1:
condition = pRecordBook[j]->getID() < pRecordBook[i]->getID();
break;
case 2:
condition = pRecordBook[j]->getName() < pRecordBook[i]->getName();
break;
case 3:
condition = pRecordBook[j]->getQuantity() < pRecordBook[i]->getQuantity();
break;
case 4:
condition = pRecordBook[j]->getPrice() < pRecordBook[i]->getPrice();
break;
default:
std::cout << "\nError concurred - sorting bv default: Name";
condition = pRecordBook[j]->getName() < pRecordBook[i]->getName();
break;
}
if(condition){
pTemp = pRecordBook[i];
pRecordBook[i] = pRecordBook[j];
pRecordBook[j] = pTemp;
toSwap = true;
}
}
if(toSwap == false)
break;
}
}
std::string searchRecord(Record *pRecordBook[], const int count, std::string id){ // Function searches for ID
for(int i = 0; i < count; i++){
if(id == pRecordBook[i]->getID())
return "\nRecord Found at Index " + std::to_string(i) + ": " + pRecordBook[i]->displayRecord();
}
return "\nRecord Not Found!";
};
std::string searchRecord(Record *pRecordBook[], const int count, std::string &input){ // Function searches for Name
for (int i = 0; i < count; i++) {
if(input == pRecordBook[i]->getName()){
return "\nRecord Found at Index " + std::to_string(i) + ": " + pRecordBook[i]->displayRecord();
}
}
return "\nRecord Not Found!";
};
void printReport(Record recordBook[], const int count){ // Prints Inventory Report
double totalValue = 0.0;
for(int i = 0; i < count; i++)
totalValue += recordBook[i].getPrice();
std::cout << "Report:\nTotal Number of items: " << std::to_string(count) << "\nTotal worth of Inventory: $";
std::cout << std::setprecision(2) << std::fixed << totalValue;
};
void displayOptions(int &choice){ // Displays Main Menu
std::cout
<< "\n1: Print Inventory Unsorted"
<< "\n2: Sort in ascending order by any field"
<< "\n3: Search for an item by ID or name"
<< "\n4: Print Report with total count and worth of inventory"
<< "\nChoose an Option: ";
std::cin >> choice;
}
Upvotes: 1
Views: 45
Reputation: 51845
Your sorting logic is flawed!
First, the toSwap
check will end the sorting prematurely (in most cases). For example, as soon as the i
loop runs and finds no value less than that at the current i
index, the search will stop. So, in a list of 3 items, with quantities of (in the unsorted list) 1
, 3
and 2
, then toSwap
will be false
at the end of the first loop but the 3
and 2
still need to be swapped.
So, first fix: remove
if (toSwap == false)
break;
and, thus, you can remove the toSwap
variable completely!
Second, the 'test' condition of you inner (j
) loop is really weird! You must run to the end of the list each time.
So, second fix: change
for(int j = i + 1; j < count-i-1; j++){
to
for(int j = i + 1; j < count; j++){
I have tested your given code code, with these changes made, on the following input file, and it works, as far as I can tell:
123 Cheese 5 12.30
212 Mutton 1 44.67
202 Chicken 3 12.78
363 Orange 5 6.22
327 Lemon 10 8.13
124 Butter 4 6.45
(I have no idea what your actual data values will be, of course, so I made some up!)
EDIT: Probably a new question, but there is also a problem with your "Search for an item..." options, as the compiler can't properly distinguish calls to the two searchRecord
functions. The two calls:
searchRecord(pRecordBook, count, inputID);
searchRecord(pRecordBook, count, inputName);
have exactly the same profile.
Upvotes: 1