Clarification on question

Just wanted clarification that I did what this was asking, as it's for homework. The code runs, compiles, and displays what is intended. I'm just not exactly sure that this is what it was asking for. I googled looping construct and everything that popped up was simply tutorials on for, while, etc loops.
Question:

Write a program that accepts 10 individual values of gallons, one at a time, and converts
each value entered to its liter equivalent before the next value is requested.

NOTE: 1 US gallon = 3.79 Liters
Use a looping construct


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
#include <iostream>
#include <conio.h>

using namespace std;

void adding();

int main() {

	adding();
	_getch();
	return 0;
}

void adding() {
	int foo[10]; //Sets total of array
	for (int i = 0; i <= 9; i++) {
		cout << "How many gallons?" << endl;
		cin >> i[foo];
		double total;
		total = i[foo] * 3.79; //Liter conversion
		cout << "Your gallons are equal to " << total << " liters" << endl;
	}
}

Thank you.
Write a program that accepts 10 individual values of gallons, one at a time, and converts
each value entered to its liter equivalent before the next value is requested.

NOTE: 1 US gallon = 3.79 Liters
Use a looping construct

The assignment doesn't say anything about using arrays or calculating the sum, nor that you should use a function for that.
I talked to my professor about using functions and what not in the past, stuff that hasn't been taught yet and she said that it was more than okay. I guess this was just the way my brain decided to code it.

As far as looping construct, is that just another term for using a loop? That was my issue, I wasn't exactly sure what that was asking for.
As far as looping construct, is that just another term for using a loop?

English is not my native language but I guess it means the same.
Slightly unorthodox, but nice.

However, you don't actually need an array. You use the input value within the same iteration and don't need it later. Hence, no need to save them all.

Do the gallons have to be integers? Could you allow the user to enter 2.5 gallons?


Your loop range (int i = 0; i <= 9; i++) is correct, but it could be written ( int i = 0; i < 10; ++i ).

Why? In both the 'i' gets values [0..9], but on the latter it is more plainly written that the 'i' gets '10' different values.
(The ++i vs i++ is a separate issue.)


One more thing: the user can become silly and write something else than valid numbers. A more strict program would test each input for failures and react appropriately: for example either abort looping or remove error and try again.
However, you don't actually need an array. You use the input value within the same iteration and don't need it later. Hence, no need to save them all.


You're right, I don't know why I used an array. I guess when I read the directions for some reason I felt like I should use one.

(The ++i vs i++ is a separate issue.)


What's the difference here, I've only ever seen it written as i++ in examples and videos that I have watched.

Do the gallons have to be integers? Could you allow the user to enter 2.5 gallons?


Good point, I'll change it to doubles.

One more thing: the user can become silly and write something else than valid numbers. A more strict program would test each input for failures and react appropriately: for example either abort looping or remove error and try again.

Another good point, I'll add in a check for numbers less than 0, (obviously you can't have negative amounts of liquid) and for characters.
Sadly.. I just typed up a really long post and it ran into an error. Guess I better copy what I type before I attempt to post it lol

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
#include <iostream>
#include <conio.h>

using namespace std;

void adding();

int main() {

	adding();
	_getch();
	return 0;
}

void adding() {
	for (double i = 0; i <= 9; i++) {
		cout << "How many gallons?" << endl;
		cin >> i;
		while (i <= 0) {
			cout << "Invalid input" << endl;
			cout << "Please enter in a valid number above 0" << endl;
			cin >> i;
	}
		double total;
		total = i * 3.79; //Liter conversion
		cout << "Your gallons are equal to " << total << " liters" << endl;
	}
}


So here is what I have updated as of now, it'll check for numbers less than 0 but after that it'll only allow you to enter in 9 valid numbers. I attempted to use cin.ignore() and clear but it didn't make a difference when I compiled.

My second issue is that, as of now if you enter in a character for the first value it will loop. I'm not exactly sure how I would check to see if a character was entered. I was reading this thread on here: http://www.cplusplus.com/forum/beginner/87409/

Specifically a post made on there:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

int main( int argc, char* argv[] )
{
    int a;
    std::cout << "Enter number between 1 and 3: ";

    while( !(std::cin >> a) || ( a < 1 || a > 3 ) )
    {
        std::cout << "Invalid input, try again: ";
        std::cin.clear();
        std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
    }

    return 0;
}


I wasn't exactly sure why variables were declared inside the ()'s for main. I'm assuming std::numeric_limits sets it so that only numerical values are able to be entered but as of now I need to read up on that.

Edit: I realized that numerical_limits isn't what I'm looking for as it sets a limit on the highest number you can enter if max.. but something similar possibly?
Last edited on
Why do you complicate it so much ?
I would do just what the assignment demands.
Write a program that accepts 10 individual values of gallons, one at a time, and converts
each value entered to its liter equivalent before the next value is requested.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <conio.h>

using namespace std;

const int MAX = 10;

int main() 
{
  double gallons = 0;

  for (int i = 0; i < MAX; i++)
  {
    cout << "\nHow many gallons: ";
    cin >> gallons;
    cout << gallons << " = " << gallons * 3.79 << " liters";
    cin.ignore(255, '\n');
  }

  _getch();
  return 0;
}


The more sophisticated the solution the less likely she thinks that you did it on your own.
Why do you complicate it so much ?


Because maybe I'm trying to learn? I'm not asking you to code what I'm asking for help on. I'm looking for a push in the right direction.
I wasn't exactly sure why variables were declared inside the ()'s for main.
int main( int argc, char* argv[] )

Command line arguments. One can start programs from command line / terminal / shell script. Some programs accept arguments. E.g.
dir
dir C:\Users
dir /S C:\Users

(the MS 'dir' is not actually a "program", but the concept of (optional) arguments is similar. For that reason the standard has more than one signature for main():
1
2
int main()
int main(int, char**)


That example program, however, does not use the function parameters at all. A compiler should/could show a "warning: unused" message.


I'm assuming std::numeric_limits sets it so that only numerical values are able to be entered but as of now I need to read up on that.

The secret of that is in the cin.ignore. It takes a number and a character. It discards characters from stream, until it either sees the <character> or has discarded <number> characters. Two ending conditions: whichever comes first.

The std::numeric_limits<std::streamsize>::max() is a very big number. It is quite likely that the call of std::ignore will return on encountering <character> which is newline.

The while-loop (yes, while and for are "loops", you are "looping", or "iterating") will repeat as long as:
1. input fails
or
2. input is too small
or
3. input is too large

If input fails, then 'a' does not have a valid value. Due to the nature of logical OR, there is no need to evaluate the second condition. Logical AND is similarly "lazy"; it will not evaluate both conditions, if the first one is false (which alone ensures that entire AND is false).


In your case it is enough to have two conditions: input is successful and 'a' is not negative.

What the while-loop in that program does is to set the value of 'a'. You just have to repeat it 10 times.


Your second attempt does have a flaw:
1
2
3
4
for ( double bar = 0; bar <= 9; bar++ )
{
  cin >> bar; // what if I type 42 on first time? Or 7 every time?
}

You want the loop to repeat exactly 10 times, no matter what (valid input) I do type. The variable that you do store the input into must be thus be different from the loop counter. In the first program you did have a separate variable; actually a whole array of them (foo).

Furthermore, the loop counter is better to be integral; floating-point math is not as intuitive as one expects.


In your first program you (could have) had essentially this construct:
1
2
3
double foo[10];
int bar = 7;
std::cout << bar[foo];

It, bar[foo], is non-conventional, but legal. The foo is treated like a pointer (double*) and the operator [] can be replaced with:
1
2
3
4
5
6
7
bar[foo]
<=>
*(bar + foo)
<=>
*(foo + bar)
<=>
foo[bar]

The last version is the conventional syntax: arrayname [ index ]
I'm looking for a push in the right direction.

What is the right direction ?
In my opinion it's doing the assignments with the techniques you have learned so far in the way they are supposed to be done. Of course it's just my personal opinion - other people have other opinions and that is fine.
What is the right direction ?
In my opinion it's doing the assignments with the techniques you have learned so far in the way they are supposed to be done. Of course it's just my personal opinion - other people have other opinions and that is fine.


I don't know, I see what you're saying. I guess my issue is that whenever I write something in c++ I end up over thinking it.

This is what I have as of now:

The ONLY issue I've had while testing it so far is that if I enter in a character after a number, it will fall through and then after display that there was an error.

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
#include <iostream>
#include <conio.h>

using namespace std;

void adding();

int main() {

	adding(); //Function call
	_getch();
	return 0;
}

void adding() {
	double foo[10]; //Array for gallons
	for (int i = 0; i <= 9; i++) { //I is the counter
		cout << "How many gallons?" << endl;
		cin >> i[foo]; //Stores how many gallons in array

		while (i[foo] < 0 || cin.fail()) { //While input is invalid
			cin.clear(); //Clears the error flag
			cin.ignore(256, '\n'); //Skip 256 characters or until newline
			cout << "You entered in invalid input" << endl;
			cout << "Please enter in valid input" << endl;
			cin >> i[foo]; //Stores new value in array
		}
		double total;
		total = i[foo] * 3.79; //Liter conversion
		cout << "Your gallons are equal to " << total << " liters" << endl;
	}
}


I was thinking that I might be able to use something like isDigit to fix this issue though as decimal numbers are 0-9
You are back to the array.

1. Make foo a single double, not an array.
2. Replace every occurrence of i[foo] with foo


Change the order of the two tests on line 21. As it is now, you do test the value from input before you know whether the input did succeed or not.
This is what I changed it to, I'm still having the same issue where it will fall through. I added in the if statement in an attempt to check it but it still falls through with the input.

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
#include <iostream>
#include <conio.h>

using namespace std;

void adding();

int main() {

	adding(); //Function call
	_getch();
	return 0;
}

void adding() {
	double foo; 
	for (int i = 0; i <= 9; i++) { //I is the counter
		cout << "How many gallons?" << endl;
		cin >> foo; //Stores how many gallons

		while (cin.fail() || foo < 0) { //While input is invalid
			cin.clear(); //Clears the error flag
			cin.ignore(256, '\n'); //Skip 256 characters or until newline
			cout << "You entered in invalid input" << endl;
			cout << "Please enter in valid input" << endl;
			cin >> foo; //Stores new value
		}

		if (!cin.fail() && foo > 0) {
			double total;
			total = foo * 3.79; //Liter conversion
			cout << "Your gallons are equal to " << total << " liters" << endl;
		}
	}
}
What's happening I believe is that it's storing the number first if you entered 10 for input then space A. It checks the 10, goes through and then prompts you for valid input because the A was incorrect.

Then if you have a10 for example, it'll tell you input is invalid off the bat, because it's checking a first.
Since you check the input using the while (cin.fail() || foo < 0) at line 21, there's no need to test it all over again with an if statement at line 29. Remove this: if (!cin.fail() && foo > 0 as it is redundant.

Regarding the invalid input, "if you entered 10 for input then space A", one solution is to always do the cin.ignore(256, '\n');, even after getting a valid input.


Now a suggestion. Since you like the idea of using functions, you can use them to make the program more readable. Simply lifting the entire program logic out of main() and dropping into a function adding() doesn't particularly aid legibility.

What I'd suggest instead is that since the getting of user input has now become quite complex, make that into a separate function. I'd also make the conversion calculation, though simple, into a separate function. Then main() could look something like this:
1
2
3
4
5
6
7
8
9
10
11
int main()
{
    for (int i = 0; i < 10; ++i)
    {
        double gallons = get_input("How many gallons?");
        double liters = gallons_to_liters(gallons);
        cout << gallons << " gallons are equal to " << liters << " liters\n";
    }

    _getch();
}

With the use of suitable well-chosen variable and function names, you can see at a glance what the program is doing, without even needing additional comments. By passing a suitable prompt string to the function get_input(), that function can re-prompt with that if necessary, instead of a generic message.


p.s. Another advantage, apart from improved legibility, is re-usability. Once you have a working and tested function such as get_input() and you are happy with it, you could use it again in other future projects. It's useful to think of functions in this way, write simple functions which do one thing, and do it well, and the chances of being able to use them again increases, which aids future productivity.
Last edited on
p.s. Another advantage, apart from improved legibility, is re-usability.


This makes a lot of sense, I never thought of it like that. I "sometimes" have been using multiple functions to break it up, but in this case I figured since it was so small it didn't make much of a difference. I'll have to start saving or making notes of functions that I make that could possibly be used in the future. Thank you.
Topic archived. No new replies allowed.