2

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;
} 
1
  • 1
    There are so many problems with your code, it's hard to know where to start, and it seems like you must not be paying attention in class. For instance, most of your functions take parameters, but you're not passing any arguments to them. They do everything in local variables, so there's no way for what one function does to affect the next. Commented Jul 26, 2015 at 5:22

3 Answers 3

4

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"

  1. 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.

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

  3. 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.

  4. There are other issues, too.

Sign up to request clarification or add additional context in comments.

1 Comment

Very helpful, thank you. I've made some of the changes you recommended and it has reduced the amount of errors significantly. I only have 2 errors when I compile now, rather than 30! 1. In main, struct bookTable *book_table = setArray() - says too few arguments 2. In setArray, bookTable *Book = new bookTable[arraySize]; says redefinition of formal parameter 'Book'. Not really sure what either means. Thanks for your help! And we have not been taught vectors yet, so don't think I can use them just yet :)
0

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

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.