简体   繁体   English

如何构造可以使用指针成员对指针数组进行排序的 function

[英]How to structure a function that can Sort an Array of Pointers using the pointer members

New CS Student in need of direction/help.需要指导/帮助的新 CS 学生。 I trying to sort my pRecordBook Array by the class member picked on user end.我试图通过在用户端选择的 class 成员对我的pRecordBook数组进行排序。 But for some reason when executing my comparison is just voided or not taken.但是由于某种原因,在执行我的比较时只是作废或不采取。

clang 11.0.3 Xcode 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 .我已经向后工作,甚至插入了我的常规数组,选择了一个条件,将其硬编码在if 语句中 - Boom Works - 繁荣工程

I've then included the switch statement because I had thought the break;然后我包含了switch 语句,因为我想到了break; in the switch was causing me to get kicked out of my nested loops killing the function in doing so.开关中导致我被踢出嵌套循环,这样做会杀死 function。 - Nope works - 不工作

It's when I have the Pointers Array plugged in that the comparison fails.当我插入指针数组时,比较失败。 Is there a cast I am missing or?有没有我失踪的演员?

Thank you for your time!感谢您的时间!

// 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;
}

Your sorting logic is flawed!您的排序逻辑有缺陷!

First, the toSwap check will end the sorting prematurely (in most cases).首先, toSwap检查会提前结束排序(在大多数情况下)。 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.例如,一旦i循环运行并且没有找到小于当前i索引处的值,搜索就会停止。 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.因此,在 3 个项目的列表中,数量为(在未排序的列表中) 132 ,然后toSwap在第一个循环结束时将为false ,但32仍需要交换。

So, first fix: remove所以,首先修复:删除

   if (toSwap == false)
       break;

and, thus, you can remove the toSwap variable completely !因此,您可以完全删除toSwap变量!

Second, the 'test' condition of you inner ( j ) loop is really weird!其次,你内部( j )循环的“测试”条件真的很奇怪! 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.编辑:可能是一个新问题,但您的“搜索项目...”选项也存在问题,因为编译器无法正确区分对两个searchRecord函数的调用。 The two calls:两个调用:

searchRecord(pRecordBook, count, inputID);
searchRecord(pRecordBook, count, inputName);

have exactly the same profile.具有完全相同的配置文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM