Hello AcesHigh1919,
Along with
salem c's advice here are some things that should help.
In the beginning you have:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <string>
const char FileName[] = "recipe.txt";
using namespace std;
double OG, FG, ABV;
string maltType, yeastType, grainType, hopType;
char choice;
void ABVCALC();
void Recipe();
void Menu();
void viewRecipe();
|
And this is what I see:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
#include <cctype> // <--- std::tolower() and std::toupper().
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>
#include <fstream>
//const char FileName[] = "recipe.txt"; // <--- Not needed here.
//using namespace std; // <--- Best not to use.
// The most recent post that is worth reading. http://www.cplusplus.com/forum/beginner/258335/
// <--- An alternative that has a more narrow focus.
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::ifstream;
using std::ofstream;
// <--- Avoid using global variables like these.
//string maltType, yeastType, grainType, hopType; // <--- Never used.
// <--- Moved other variables to the functions that need them.
void ABVCALC();
void Recipe();
void Menu();
void viewRecipe();
|
First you included "cstring", but you never use anything from that header file. I changed it to "cctype" because you could use that more.
If you are thinking that
const char FileName[] = "recipe.txt";
requires the "cstring" header file it does not. For the variable name as a constant it should be in all caps. Like, "FILENAME" or "FILE_NAME". The underscore is the old DOS method of showing a space where one is not allowed.
Global variables are not a good idea. Anything below their definition could change their value and then it becomes hard to find where it went wrong. Global variables should be defined in "main" and passed to the functions that need them or defined in the functions that need them.
If your compiles allows
void main()
. Then I would guess that it is ole and should be adjusted or updated to use the C++11 standards at the minimum.
Also I am thinking that if your compiler is that old to allow
void main()
it should be
void main(void)
.
I am not sure when it started, but I do know, from C++11 on it should be
int main()
.
The more proper use of "main" is to direct the flow of the program not send it to a function that is the program.
The "menu" function should do one thing and return to "main" to continue with the program.
Looking at the output:
Welcome to The Home-brew Homie
What would you like to do?
A. Alcohol By Volume Calculator
C. Create A Recipe
R. View Your Recipes
E. Exit
Enter choice:
|
Forgive me and bear with me. Time experience and just working with output like this has taught me to to make it easier and nicer to read. IMHO I think it looks better than having every line all run together, which is harder to read.
To show you what I mean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
char Menu()
{
char choice; // <--- Moved from global variable and put here where it is the only place it is used.
cout << '\n' << std::string(8, ' ') << "Welcome to The Home-brew Homie\n";
cout << "\nWhat would you like to do? \n";
//cout << "A. Alcohol By Volume Calculator" << endl << "C. Create A Recipe" << endl << "R. View Your Recipes" << endl << "E. Exit" << endl;
do
{
cout // <--- Same as above, but easier to read and adjust.
<< "\nA. Alcohol By Volume Calculator\n"
<< "C. Create A Recipe\n"
<< "R. View Your Recipes\n"
<< "E. Exit\n"
<< "Enter choice: ";
cin >> choice;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // <--- Requires header file <limits>.
choice = std::toupper(choice);
if (choice != 'A' && choice != 'C' && choice != 'R' && choice != 'E')
std::cout << "\n Invalid choice! Try again.\n";
} while (choice != 'A' && choice != 'C' && choice != 'R' && choice != 'E');
return choice;
}
|
You could move lines 8 and 9 down to 16 and just loop from the "cin" on only printing the heading and menu once. It is up to you and what you want.
Line 17 is used to clear the "\n" from the input buffer following the formatted input of
cin >> choice;
which leaves the "\n" in the input buffer. This could be a problem later on.
This "cin.ignore()" statement is the more portable way of writing this that any compiler can use. The first parameter is just a large number. That big fancy first parameter is what any compiler and header file can use to get a large number based on the way the header file is written. And yes between compiles the hearer can be different. Or as you may find "1000" is quite often used as the first parameter and works fine. Either way it will ignore the number of characters of the first parameter or the "\n" whichever comes first.
I know I said that a function should do one thing, but I tend to make a "menu" function an exception.
Now when you return a valid input to main there you can use your if statements or a switch to call your other functions.
I have only worked on the "" function so far. This should do you better than what you started with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
int viewRecipe()
{
string line;
ifstream myfile("recipe.txt");
if (!myfile)
{
std::cout << "\n File \"" << "recipe.txt" << "\" did not open.\n";
return 1; // <--- Any number > 0 denotes an error or problem.
}
std::cout << '\n';
while (getline(myfile, line))
{
cout << line << endl;
}
myfile.close();
return 0;
}
|
And the function call back in "main" would be:
1 2 3
|
// <--- Function call.
if (viewRecipe()) // <--- Since any number > 0 is considered true.
return 1;
|
Since this would be in "main" this would leave the program.
The if statement deals with opening and if there is a problem it leaves the function. Any number used with the "return" that is > 0 denotes a problem.
Some helpful tips. When I first "OG" and "FG" I had no idea what they were. As capital letters I thought they were defined as constants. Try to avoid capital letters ans single letters for variable names. It is better to spell them out or give them a proper name that has some meaning. This is mostly for your benefit, but helps others.
For the function names:
1 2 3 4
|
void ABVCALC(); // <--- avoid all capital letters. "CalcABV" might be a better name.
void Recipe(); // <--- OK, but some would say start with a lower case letter.
void Menu();
void viewRecipe(); // <--- Be consistent. The use of "camelCase" is good.
|
How you name functions and variables is still your choice, but you should find a style that you like and stick with it.
Learn to make use of blank lines in your code. It makes it much easier to read and fix. Again mostly for your benefit, but it does help when posting code here. The easier it is to read the quicker you are to get a response.
If I managed to forget something, and I probably did, I will get it later.
Andy