简体   繁体   中英

Structs, Arrays, and Functions C++

I'm completely stuck on this assignment. I first wrote everything in int main() without any issue. It all worked lovely! Unfortunately our instructor wants it split up into multiple functions (less than 35 lines per function). I've split it up as you can see below but unfortunately my knowledge (and google hasn't been much help) of functions and passing/referencing through them is not that high. My program doesn't work at all now. All the 'Books' give errors so i'm not sure if I'm passing the struct or array improperly. Please help!

The original txt file reads like:

number of books
title
author
price
title
author
price

Code:

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

using namespace std;

void setStruct() {

    struct bookTable {
        string title;
        string author;
        double price;
    };
}

void setArray(int &arraySize, struct bookTable *Book[]) {

    ifstream infile;
    int bookCounter = 0;

    infile.open("books2.txt");

    if (!infile) {
        cout << "Unable to open Books.txt" << endl;
    }

    infile >> arraySize;
    infile.ignore(100, '\n');

    bookTable *Book = new bookTable[arraySize];

    infile.close();
}

void readFile(struct bookTable *Book[]) {

    ifstream infile;
    int bookCounter = 0;

    infile.open("books2.txt");

    for (int i = 0; getline(infile, Book[i].title); i++) {

        getline(infile, Book[i].author, '\n');
        infile >> Book[i].price;
        infile.ignore(100, '\n');

        bookCounter++;
    }

    infile.close();
}

void displayMenu(struct bookTable *Book[]) {
    int menuChoice = 0, bookCounter = 0;
    string findTitle;

    do { cout << "\n===== Bookstore App =====" << endl; 
    cout << "1. Print Books" << endl; 
    cout << "2. Change Price" << endl;
    cout << "3. Quit" << endl; 
    cout << "\nEnter Choice: ";
        cin >> menuChoice;
        if (menuChoice == 1) {
            for (int i = 0; i < bookCounter; i++) {
                cout << "===== BOOK =====" << endl;
                cout << "Title: " << Book[i].title << endl;
                cout << "Author: " << Book[i].author << endl;
                cout << "Price: " << fixed << setprecision(2) << Book[i].price << endl; } }
        else if (menuChoice == 2) { cin.ignore(100, '\n');
            cout << "What is the title of the book? ";
            getline(cin, findTitle, '\n');
            for (int i = 0; i < bookCounter; i++) {
                if (findTitle == Book[i].title) {
                    cout << "Enter New Price: " << endl;
                    cin >> Book[i].price;
                }
                else if (findTitle != Book[i].title) {
                    cout << "Unable to find Book" << endl;
                }}}

        else if (menuChoice < 1 || menuChoice > 3) {

            cout << "Invalid Entry. Please enter 1, 2, or 3 from the options menu." << endl;
        }   } while (menuChoice != 3);
}

void writeFile(int arraySize, struct bookTable *Book[]) {

    ofstream outfile;
    int bookCounter = 0;

    outfile.open("sale2.txt");

    outfile << arraySize << endl;

    for (int i = 0; i < bookCounter; i++) {

        outfile << Book[i].title << endl;
        outfile << Book[i].author << endl;
        outfile << fixed << setprecision(2) << Book[i].price << endl;
    }

    outfile.close();

    delete[] Book;

}

int main() {

    setStruct();
    setArray();
    readFile();
    displayMenu();
    writeFile();

    cout << "\nSale2.txt has been created." << endl;

    return 0;
} 

I haven't compiled or run this, but hopefully it will get you started in the right direction:

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

using namespace std;

// This declares "struct bookTable"
// You need to actually define a variable of this type later in your program
struct bookTable {
    string title;
    string author;
    double price;
};

bookTable * setArray(int &arraySize, struct bookTable *Book[]) {

    ifstream infile;
    int bookCounter = 0;

    infile.open("books2.txt");

    if (!infile) {
        cout << "Unable to open Books.txt" << endl;
    }

    infile >> arraySize;
    infile.ignore(100, '\n');

    bookTable *Book = new bookTable[arraySize];

    infile.close();

    // This returns an empty array of bookTable[]
    return Book;
}

void readFile(struct bookTable *Book) {

    ifstream infile;
    int bookCounter = 0;

    infile.open("books2.txt");

    for (int i = 0; getline(infile, Book[i].title); i++) {

        getline(infile, Book[i].author, '\n');
        infile >> Book[i].price;
        infile.ignore(100, '\n');

        bookCounter++;
    }

    infile.close();
}

void displayMenu(struct bookTable *Book[]) {
    int menuChoice = 0, bookCounter = 0;
    string findTitle;

    do { cout << "\n===== Bookstore App =====" << endl; 
    cout << "1. Print Books" << endl; 
    cout << "2. Change Price" << endl;
    cout << "3. Quit" << endl; 
    cout << "\nEnter Choice: ";
        cin >> menuChoice;
        if (menuChoice == 1) {
            for (int i = 0; i < bookCounter; i++) {
                cout << "===== BOOK =====" << endl;
                cout << "Title: " << Book[i].title << endl;
                cout << "Author: " << Book[i].author << endl;
                cout << "Price: " << fixed << setprecision(2) << Book[i].price << endl; } }
        else if (menuChoice == 2) { cin.ignore(100, '\n');
            cout << "What is the title of the book? ";
            getline(cin, findTitle, '\n');
            for (int i = 0; i < bookCounter; i++) {
                if (findTitle == Book[i].title) {
                    cout << "Enter New Price: " << endl;
                    cin >> Book[i].price;
                }
                else if (findTitle != Book[i].title) {
                    cout << "Unable to find Book" << endl;
                }}}

        else if (menuChoice < 1 || menuChoice > 3) {

            cout << "Invalid Entry. Please enter 1, 2, or 3 from the options menu." << endl;
        }   } while (menuChoice != 3);
}

//  !!! DON'T UNCOMMENT THIS UNTIL YOU FIGURE OUT HOW TO PRESERVE "arraySize" !!!
//      Suggestion: use a C++ "vector<>" instead of an array...
//    void writeFile(int arraySize, struct bookTable *Book[]) {
//    
//      ofstream outfile;
//      int bookCounter = 0;
//    
//      outfile.open("sale2.txt");
//    
//      outfile << arraySize << endl;
//    
//      for (int i = 0; i < bookCounter; i++) {
//    
//          outfile << Book[i].title << endl;
//          outfile << Book[i].author << endl;
//          outfile << fixed << setprecision(2) << Book[i].price << endl;
//      }
//    
//      outfile.close();
//    
//      delete[] Book;
//    
//    }

int main() {

    // setStruct();  // Not needed
    struct bookTable *book_table = setArray();  // Allocate space
    readFile(book_table);  // Initialize data
    displayMenu(book_table); // use book_table
    // writeFile(); // TBD

    cout << "\nSale2.txt has been created." << endl;

    return 0;
} 

Key notes:

  1. When you had everything in "main()", all of your code had visibility to all of your variables.

  2. When you moved everything into separate functions, the functions could no longer "see" these variables.

    This is called "scope"

  3. One solution is to put everything back in "main()". This is Bad.

    Another solution is to make your variables all global. This, too, is Bad.

    A good solution is to declare the variables you need to share in "main()", but then pass them as parameters . This is what I've shown above.

  4. An even better, more advanced solution, might be to refactor your program into classes .

  5. Since you're programming in C++, and since you have a variable number of elements, it would probably be a good idea to change your array into a C++ vector . This has several advantages, including:

    a. You'd no longer need to read the entire file just to find the #/elements - you could simply add new elements as you go.

    b. You can always query "vector.size()" to find the current #/elements.

  6. There are other issues, too.

I hope that helps ... and please post back if you have any questions.

Couple of things:
-Your struct doesn't need to be inside of the setStruct function, the setStruct should be used to send data to an existing struct (example below)
-setArray isn't being passed any parameters when it's being called (It needs (int &arraySize, struct bookTable *Book[]) ) and neither are some of your other functions, this means that they don't actually have any data to modify.
They should be called like this: setArray(size of array, struct being passed to it);

Also, an example of how setStruct and the struct should be defined seperately:

struct bookTable {
    string title;
    string author;
    double price;
};
void setStruct(&struct x, string title, string author, double price) {
    x.title  = title;
    x.author = author;
    x.price  = price;

}

Make sure to pay attention to what each of these functions are doing so that you know what parameters to pass to them and better understand the code overall.
By splitting main() into a bunch of functions you aren't really doing much besides making your code modular and legible

Also, posting the exact errors that you're getting will help, as I imagine that even after you fix these things I mentioned I might not work perfectly

For starters:

void setStruct() {

    struct bookTable {
        string title;
        string author;
        double price;
    };
}

You create a function setStruct() then use it several times in other functions without accessing the function itself. Why not place the struct in its global scope that way you can use it in Main() or anywhere else and pass the struct declaration freely between functions?

Also:

for (int i = 0; getline(infile, Book[i].title); i++) {

    getline(infile, Book[i].author, '\n');
    infile >> Book[i].price;
    infile.ignore(100, '\n');

    bookCounter++;
}

You pass a use Book as if it is in scope where you have declared it and potentially defined it. However, you pass it through a function - meaning the struct type is now out of scope and will need to access its elements through a pointer. So your code will need to be adjusted as such:

void readFile(struct bookTable *Book[]) {

    ifstream infile;
    int bookCounter = 0;

    infile.open("books2.txt");

    for (int i = 0; getline(infile, Book[i]->title); i++) {

        getline(infile, Book[i]->author, '\n');
        infile >> Book[i]->price;
        infile.ignore(100, '\n');

        bookCounter++;
    }

    infile.close();
}

Notice that every place you had Book[i].variable is now Book[i]->variable - Hopefully this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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