Trouble with viewing a file.

I am new to learning C++ and am having the hardest time reading the .txt doc. Everything works except for the "View my recipe" section

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#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();




void main()
{
	Menu();
}
void Menu()
{
	cout << "Welcome to The Homebrew Homie" << endl;
	cout << "What would you like to do?  " << endl;
	cout << "A.   Alcohol By Volume Calculator" << endl << "C.   Create A Recipe" <<endl<< "R.   View Your Recipes"<<endl << "E.   Exit" << endl;
	cin >> choice;
	if (choice == 'A' || choice == 'a' || choice == 'A.' || choice == 'a.')
	{
		ABVCALC();
	}
	if (choice == 'C' || choice == 'c' || choice == 'C.' || choice == 'c.')
	{
		Recipe();
	}
	if (choice == 'R' || choice == 'r' || choice == 'R.' || choice == 'r.')
	{
		viewRecipe();
	}
	if (choice == 'E' || choice == 'e' || choice == 'E.' || choice == 'e.')
	{
		return;
	}
	else
		cout << "That is an invalid option. Please enter again: ";
}
void ABVCALC()
{
	cout << "Great choice, lets crunch some numbers. What was your reading for original gravity of your homebrew? ";
	cin >> OG;
	cout << endl << "Great, and what was your reading for your final gravity? ";
	cin >> FG;
	ABV = (((((OG - FG) * 1.05) / FG) / 0.79) * 100);
	cout << endl << endl << "Your homebrew's alcohol by volume or ABV for short is " << ABV << "%";
	return;
}
void Recipe()
{
	ofstream outfile;
	outfile.open("recipe.txt", std::ios_base::app); 
	string cont;
	const int ingr = 4;
	ifstream infile;
	string beer[ingr] = { "malt bags","oz of grain","oz of hops","packs of yeast" };
	double added[ingr], totalBoil, grainSteep, batchSize;
	string addHops, hopOz, hopType;
	char hopsChoice;
	string type[ingr] = { "malt", "grain", "hops", "yeast" };
	string typeAdded[ingr];
	for (int i = 0; i < ingr; i++)
	{
		cout << "How many " << beer[i] << " did you use in this recipe?  ";
		cin >> added[i];
		if (added[i] < 0)
		{
			cout << "That is an invalid option. Please try again." << endl;
			cout << "How many " << beer[i] << " did you use in this recipe?  ";
			cin >> added[i];
		}
		cout << "What type of " << type[i] << " was used?  ";
		cin >> typeAdded[i];
	}
	cout << "How many gallons is this recipe for? ";
	cin >> batchSize;
	cout << "How many minutes did you steep the grains? ";
	cin >> grainSteep;
	cout << "How many minutes was the total boil time? ";
	cin >> totalBoil;
	cout << "How many minutes till you added the hops? ";
	cin >> addHops;
	
	outfile<< "              Final Ingredient List " << endl << "___________________________________________________________" << endl << beer[0] << " --- " << added[0] << ' ' << typeAdded[0] << endl<<beer[1] << " --- " << added[1] << ' ' << typeAdded[1] <<endl<< beer[2] << " --- " << added[2] << ' ' << typeAdded[2] <<endl<< beer[3] << " --- " << added[3] << ' ' << typeAdded[3] << endl << endl << endl<<"                     Recipe" << endl << "___________________________________________________________" << endl<< "Bring " << batchSize << " gallons of water to a boil and then shut off the heat." << endl<< "Mix in malt until fully disolved." << endl << "Add grain to steepbag and steep for " << grainSteep << " minutes. You now have a wart" << endl<< "Bring your wart to a boil." << endl << "After " << addHops << " minutes of boil, add the hops. Be careful as the wart may begin to boil over if not watched closely." << endl<< "After " << totalBoil << " minutes of total boiling turn heat off and wait for the brew to cool to about 70 degrees F."<<endl<< "Transfer to the container that you plan to finish the brewing process in. Make sure the container will be airtight. "<<endl<< "Add in the yeast and the seal container. Be sure to add a one way air flow valve to the top so that the CO2 can escape." << endl<<"after one weeks time transfer the brew to another container being sure to leave the sludge at the bottem in the first container."<<endl<<"This sludge is the dead yeast colonies and will make your brew taste bitter."<<endl<< "After one more week, transfer the brew to a keg or bottles and start the carbonation process."<<endl<<endl;
	cin.ignore();
	outfile.close();
}
void viewRecipe()
{
	string line;
	ifstream myfile("recipe.txt");
	if (myfile.is_open())
	{
		while (myfile.good())
		{
			getline(myfile, line);
			cout << line << endl;
		}
		myfile.close();
	}

	else cout << "Unable to open file";

	return;
}
Last edited on
Dude!, newlines in your source code please.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
outfile<< "              Final Ingredient List " << endl 
    << "___________________________________________________________" << endl 
    << beer[0] << " --- " << added[0] << ' ' << typeAdded[0] << endl
    << beer[1] << " --- " << added[1] << ' ' << typeAdded[1] <<endl
    << beer[2] << " --- " << added[2] << ' ' << typeAdded[2] <<endl
    << beer[3] << " --- " << added[3] << ' ' << typeAdded[3] << endl
    << endl
    << endl
    << "                     Recipe" << endl
    << "___________________________________________________________" << endl
    << "Bring " << batchSize << " gallons of water to a boil and then shut off the heat." << endl
    << "Mix in malt until fully disolved." << endl
    << "Add grain to steepbag and steep for " << grainSteep << " minutes. You now have a wart" << endl
    << "Bring your wart to a boil." << endl
    << "After " << addHops << " minutes of boil, add the hops. Be careful as the wart may begin to boil over if not watched closely." << endl
    << "After " << totalBoil << " minutes of total boiling turn heat off and wait for the brew to cool to about 70 degrees F."<<endl
    << "Transfer to the container that you plan to finish the brewing process in. Make sure the container will be airtight. "<<endl
    << "Add in the yeast and the seal container. Be sure to add a one way air flow valve to the top so that the CO2 can escape." << endl
    << "after one weeks time transfer the brew to another container being sure to leave the sludge at the bottem in the first container."<<endl
    << "This sludge is the dead yeast colonies and will make your brew taste bitter."<<endl
    << "After one more week, transfer the brew to a keg or bottles and start the carbonation process."<<endl
    << endl;


Then there are these errors.
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
$ g++ foo.cpp
foo.cpp:29:50: warning: multi-character character constant [-Wmultichar]
  if (choice == 'A' || choice == 'a' || choice == 'A.' || choice == 'a.')
                                                  ^
foo.cpp:29:68: warning: multi-character character constant [-Wmultichar]
  if (choice == 'A' || choice == 'a' || choice == 'A.' || choice == 'a.')
                                                                    ^
foo.cpp:33:50: warning: multi-character character constant [-Wmultichar]
  if (choice == 'C' || choice == 'c' || choice == 'C.' || choice == 'c.')
                                                  ^
foo.cpp:33:68: warning: multi-character character constant [-Wmultichar]
  if (choice == 'C' || choice == 'c' || choice == 'C.' || choice == 'c.')
                                                                    ^
foo.cpp:37:50: warning: multi-character character constant [-Wmultichar]
  if (choice == 'R' || choice == 'r' || choice == 'R.' || choice == 'r.')
                                                  ^
foo.cpp:37:68: warning: multi-character character constant [-Wmultichar]
  if (choice == 'R' || choice == 'r' || choice == 'R.' || choice == 'r.')
                                                                    ^
foo.cpp:41:50: warning: multi-character character constant [-Wmultichar]
  if (choice == 'E' || choice == 'e' || choice == 'E.' || choice == 'e.')
                                                  ^
foo.cpp:41:68: warning: multi-character character constant [-Wmultichar]
  if (choice == 'E' || choice == 'e' || choice == 'E.' || choice == 'e.')
                                                                    ^
foo.cpp:19:11: error: ‘::main’ must returnintvoid main()
           ^


Aside from the fact that your Menu code is a bit flaky, and you have to run the code twice, it otherwise seems to work.
$ ./a.out 
Welcome to The Homebrew Homie
What would you like to do?  
A.   Alcohol By Volume Calculator
C.   Create A Recipe
R.   View Your Recipes
E.   Exit
c
How many malt bags did you use in this recipe?  3
What type of malt was used?  malt
How many oz of grain did you use in this recipe?  50
What type of grain was used?  grin
How many oz of hops did you use in this recipe?  20
What type of hops was used?  hop
How many packs of yeast did you use in this recipe?  2
What type of yeast was used?  yes
How many gallons is this recipe for? 20
How many minutes did you steep the grains? 200
How many minutes was the total boil time? 30
How many minutes till you added the hops? 30
That is an invalid option. Please enter again: $ 

$ ./a.out 
Welcome to The Homebrew Homie
What would you like to do?  
A.   Alcohol By Volume Calculator
C.   Create A Recipe
R.   View Your Recipes
E.   Exit
r
              Final Ingredient List 
___________________________________________________________
malt bags --- 3 malt
oz of grain --- 50 grin
oz of hops --- 20 hop
packs of yeast --- 2 yes


                     Recipe
___________________________________________________________
Bring 20 gallons of water to a boil and then shut off the heat.
Mix in malt until fully disolved.
Add grain to steepbag and steep for 200 minutes. You now have a wart
Bring your wart to a boil.
After 30 minutes of boil, add the hops. Be careful as the wart may begin to boil over if not watched closely.
After 30 minutes of total boiling turn heat off and wait for the brew to cool to about 70 degrees F.
Transfer to the container that you plan to finish the brewing process in. Make sure the container will be airtight. 
Add in the yeast and the seal container. Be sure to add a one way air flow valve to the top so that the CO2 can escape.
after one weeks time transfer the brew to another container being sure to leave the sludge at the bottem in the first container.
This sludge is the dead yeast colonies and will make your brew taste bitter.
After one more week, transfer the brew to a keg or bottles and start the carbonation process.


That is an invalid option. Please enter again: $ 
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
Topic archived. No new replies allowed.