C ++ Structures, Arrays and Functions
I am completely stuck with this assignment. I wrote everything in int main () first without any problem. Everything worked great! Unfortunately, our instructor wants it to be split into multiple functions (less than 35 lines per function). I split it up as you can see below, but unfortunately my knowledge (and Google didn't help much) of the functions and passing / summarizing through them is not that high. My program is not working right now. All "Books" give errors, so I'm not sure if I'm passing the structure or array incorrectly. Please, help!
The original txt file reads like this:
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;
}
source to share
I haven't compiled or run this, but hopefully it gets 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:
-
When you had everything in "main ()", all your code had visibility to all of your variables.
-
When you moved everything to separate functions, the functions could no longer "see" these variables.
This is called "scope"
-
One solution is to return everything to "main ()". This is bad.
Another solution is to make your variables global. This is also bad.
A good solution is to declare variables that you need to use in "main ()", but then pass them as parameters . This is what I showed above.
-
Better yet, a more advanced solution might be to refactor your program into classes .
-
Since you are a C ++ programmer, and since you have a variable number of elements, it would probably be a good idea to change your array to a C ++ vector . This has several benefits, including:
and. You no longer need to read the entire file to find # / elements - you could just add new elements as you go.
b. You can always ask vector.size () to find the current # / elements.
-
There are other problems as well.
I hope this helps ... and please post if you have any questions.
source to share
A couple of things:
- Your structure should not be inside the setStruct function, setStruct should be used to send data to an existing structure (example below)
-setArray is not passed in any parameters when it is called (required (int &arraySize, struct bookTable *Book[])
), and none of your other functions means that in fact they have no data to change.
They should be called like this:
setArray(size of array, struct being passed to it);
Also, an example of how setStruct and struct should be defined separately:
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 does so that you know what parameters are being passed to them and better understand the code in general.
Splitting main () into a bunch of functions that you don't actually do, besides keeping your code modular and legible
Also, posting the exact errors you are getting will help as I suppose that even after you fixed these things I mentioned I might not work perfectly
source to share
To start:
void setStruct() {
struct bookTable {
string title;
string author;
double price;
};
}
You create a function setStruct()
, then use it multiple times in other functions without accessing the function itself. Why not place the struct in its global scope so that you can use it in Main()
or elsewhere and freely pass constructive declaration 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 are passing the use Book
as if it were in the scope where you declared it and potentially defined it. However, you are passing it through a function - this means that the struct type is now out of scope and will have to access its elements through a pointer. Therefore, 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();
}
Please note that every place you had Book[i].variable
is now Book[i]->variable
- Hope this helps.
source to share