Jump to content

Before I get started, please note that I am doing this as a part of my classwork. If that bothers you, maybe just give me hints instead :)

 

Hi, I have just started learning some C++ and am trying to create a program that will ask a user for a single digit integer (1 through 9), print it out, and ask again until the user inputs the character "x"

The output I want would look like this:

Enter a non-zero integer (or x to quit): 7
Enter a non-zero integer (or x to quit): 3
Enter a non-zero integer (or x to quit): -5
Enter a non-zero integer (or x to quit): -1
Enter a non-zero integer (or x to quit): x
Program stopped.

You entered 4 integers.
2 of the integers were positive.
2 of the integers were negative.
The largest value you entered was 7.
The smallest value you entered was -5.
The sum of the 4 integers was 4.

So far, my program looks like this, but it does not run. I am having problems with the variable type.

#include <iostream>
using namespace std;

int main() {
	char user_input;
	cout << "Please enter a number (or x to stop): \n";
	cin >> user_input;

	if (user_input == "x") {
		cout << "Program stopped";
	}
	else {
		cout << "Input: " << user_input << "\n";
	}

	return 0;
}

Any help on this? Should I use a different loop other than if? Any help would be appreciated.

Link to comment
https://linustechtips.com/topic/889533-c-help-minmax-checking-wout-an-array/
Share on other sites

Link to post
Share on other sites

the if statement should read:

 

if (user_input == 'x')

because you should put single quotes around characters, as double quotes represent a string instead. Hope that helps; feel free to reply with any more questions! I taught an intro to C++ course at the local high school a year or two ago so I may be of help. :-)

Link to post
Share on other sites

18 minutes ago, thedanfiscus said:

the if statement should read:

 


if (user_input == 'x')

because you should put single quotes around characters, as double quotes represent a string instead. Hope that helps; feel free to reply with any more questions! I taught an intro to C++ course at the local high school a year or two ago so I may be of help. :-)

Thanks for this! The code runs now, however one small snag is now it spams the console with input requests or something... here are the changes I made:

#include <iostream>
using namespace std;

int main() {
    int user_input = 0;
    int integers = 0;

    cout << "Please enter an integer (or x to quit): ";
    cin >> user_input;
    while (user_input != 'x')
    {
        ++integers;
        printf("Please enter an integer (or x to quit): ");
    }
    cout << "You entered" << integers << " integers.";
    return 0;
}

The code will run and ask you for an integer, but when you enter a number it begins looping input requests infinitely until I alt f4... is there a way to have it only request one input?

Link to post
Share on other sites

1 minute ago, SgtBot said:

Thanks for this! The code runs now, however one small snag is now it spams the console with input requests or something... here are the changes I made:


#include <iostream>
using namespace std;

int main() {
    int user_input = 0;
    int integers = 0;

    cout << "Please enter an integer (or x to quit): ";
    cin >> user_input;
    while (user_input != 'x')
    {
        ++integers;
        printf("Please enter an integer (or x to quit): ");
    }
    cout << "You entered" << integers << " integers.";
    return 0;
}

The code will run and ask you for an integer, but when you enter a number it begins looping input requests infinitely until I alt f4... is there a way to have it only request one input?

Your problem here is that you cannot input a letter to an int input. This will always cause an error, it's a limitation in C++ not in your code. The only workaround is to use a char to int function. See here for more info on that: https://stackoverflow.com/questions/5029840/convert-char-to-int-in-c-and-c

If you don't understand that or it doesn't look like something your teacher would want you to have to worry about, double check the assignment requirements to make sure it should exit on a letter because that seems complicated for an intro course but it's certainly not impossible.

Link to post
Share on other sites

3 minutes ago, thedanfiscus said:

Your problem here is that you cannot input a letter to an int input. This will always cause an error, it's a limitation in C++ not in your code. The only workaround is to use a char to int function. See here for more info on that: https://stackoverflow.com/questions/5029840/convert-char-to-int-in-c-and-c

If you don't understand that or it doesn't look like something your teacher would want you to have to worry about, double check the assignment requirements to make sure it should exit on a letter because that seems complicated for an intro course but it's certainly not impossible.

Ohhhh okay that makes sense then...

It looks like you don't have to check for when the user inputs a char because it will automatically close when "x" is entered. I changed the code to use scanf instead of cin and moved the scanf line into the while loop descriptor. It works pretty good now, though I'm still not sure entirely why it works other than that it maybe throws an error when x is entered and crashes the program.

Here is the new code:

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;

int main() {
    int user_input = 0;
    int integers = 0;

    printf("Please enter an integer (or x to quit): ");
    while (scanf("%d",&user_input) == 1)
    {
        ++integers;
        printf("Please enter an integer (or x to quit): ");
    }
    cout << "You entered " << integers << " integers.";
    return 0;
}

image.png.cf108388d3728a09731d4f715e2bc3f5.png

Link to post
Share on other sites

19 minutes ago, thedanfiscus said:

If you don't understand that or it doesn't look like something your teacher would want you to have to worry about, double check the assignment requirements to make sure it should exit on a letter because that seems complicated for an intro course but it's certainly not impossible.

Type conversions should not be a problem for an intro course in my experience. In fact, they are a pretty fundamental part of getting user input from the console. By my logic, it should always be assumed that console input is a char (or a series of chars) and if you need something else, you should try to cast it when you need it to be something else; That way, you can handle the errors that show up (like what OP is experiencing) from an erroneous input.

Just for the fun, I would like to see the OP enter 2147483648 instead of the character "x" and see what happens. 

What we are experiencing here is simply mismatched types combined with unhandled exceptions.

Since @SgtBot is using Visual Studio, now would be a really good time to talk about breakpoints and program debugging.


 

ENCRYPTION IS NOT A CRIME

Link to post
Share on other sites

6 minutes ago, straight_stewie said:

Since @SgtBot is using Visual Studio, now would be a really good time to talk about breakpoints and program debugging.

Well I had to add a break point on the "return(0);" line so that the console wouldn't close out after I input x.

 

7 minutes ago, straight_stewie said:

Just for the fun, I would like to see the OP enter 2147483648 instead of the character "x" and see what happens.

image.png.464447d5ced985feb03ea29c6d82721b.png

Looks like it just accepted it as an integer... O.o

Link to post
Share on other sites

7 minutes ago, SgtBot said:

Looks like it just accepted it as an integer

I don't see how. The maximum value of system.int32 according to Microsoft and my compiler is  2,147,483,647. Therefore, 2,147,483,648 should throw an overflow exception.

Try printing the type of the input using .NET's provided GetType() method. I have a sneaking suspicion that your user input is not actually an int.
https://msdn.microsoft.com/en-us/library/system.object.gettype(v=vs.110).aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1

ENCRYPTION IS NOT A CRIME

Link to post
Share on other sites

7 minutes ago, straight_stewie said:

Try printing the type of the input using .NET's provided GetType() method. I have a sneaking suspicion that your user input is not actually an int.
https://msdn.microsoft.com/en-us/library/system.object.gettype(v=vs.110).aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1

I'm not sure how I would implement that code into my program... would i do something like:
 

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;

int main() {
    int user_input = 0;
    int integers = 0;
    int sum = 0;
    int varType = getType(integers);

    printf("Please enter an integer (or x to quit): ");
    while (scanf("%d",&user_input) == 1)
    {
        ++integers;
        sum = sum + user_input;
        printf("Please enter an integer (or x to quit): ");
    }
    cout << "\n";
  	cout << varType;
    cout << "You entered " << integers << " integers." << "\n";
    cout << "The sum of the integers was: " << sum;
    return 0;
}

 

Link to post
Share on other sites

@SgtBot

 

It's not that hard. The key is that you need to check the stream's state after the input operation. When extraction fails (because you enter a wrong type, for example) the stream state will go bad to indicate something went wrong. The offending data, however, is left in the input buffer so you can attempt to extract it again.

Here's a little example (not a full solution to your homework) :

#include <iostream>

int main()
{
	int user_input = 0;
	std::cout << "Please enter an integer (or x to quit): ";
	
	/* Attempt to read user input as integer but also check resulting
	   stream state. std::cin inherits operator bool from std::ios which
	   returns false if the stream state is bad. Trying to input a letter
	   while reading a int will result in the stream state going bad. */
	if (std::cin >> user_input)
	{
		//Successfully read a integer.
		std::cout << "You entered the integer " << user_input << '\n';
	}
	else
	{
		/* Failed to read integer, the offending data is still in the
		   input buffer. Reset stream state and attempt to read as char
		   and test the resulting stream state again. */
		std::cin.clear();

		char ch;
		if (std::cin >> ch)
		{
			//Sucessfully read a char.
			std::cout << "You entered the char " << ch << '\n';
		}
		else
		{
			//Failed to read a char.
			std::cout << "Failed to read either int or char\n";
		}
	}

	return 0;
}

 

Link to post
Share on other sites

11 hours ago, thedanfiscus said:

The only workaround is to use a char to int function.

No, conversion is not the answer here. When you ask to extract a char, a single char is what you'll get. When the user enters 1337, for example, the result of reading a char will be 49, which is the ASCII code for the character '1'. It takes a lot more work to read all the characters separately and convert them to a full integer again.

 

When you request to extract a int and the user enters 'x' the result will be a failed extraction and the stream state going bad. Nothing has actually been read and your variable will still hold whatever it held before the read operation (pre C++ 11) or 0 (post C++ 11).

 

The correct way is to make it a  habit to check the result of operations before continuing and handling problems.

Link to post
Share on other sites

10 hours ago, Unimportant said:

@SgtBot

 

It's not that hard. The key is that you need to check the stream's state after the input operation. When extraction fails (because you enter a wrong type, for example) the stream state will go bad to indicate something went wrong. The offending data, however, is left in the input buffer so you can attempt to extract it again.

Here's a little example (not a full solution to your homework) :

Well after playing around with some code for a bit, I found out I don't actually have to have the loop check for a char input to stop the program. It turns out that putting in an x or any other char will stop the program regardless. Here is the code that I have now:

#include <iostream>
using namespace std;

int main() {
	
	int userInput = 0;
	int counter = 0;
	int pos = 0;
	int neg = 0;
	int max = 0;
	int min = 0;
	int sum = 0;

	printf("Please enter a number: ");
	while (scanf("%d", &userInput) == 1) {
		
		if (userInput < 0) {
			++neg;
		}
		if (userInput > 0) {
			++pos;
		}
		if (userInput < min) {
			min = userInput;
		}
		if (userInput > max) {
			max = userInput;
		}

		++counter;
		sum = sum + userInput;
		printf("Please enter a number: ");
	
	}
	
	cout << "\nYou entered " << counter << " integers.\n";
	cout << pos << " of the integers were positive.\n";
	cout << neg << " of the integers were negative.\n";
	cout << "The largest number was " << max << "\n";
	cout << "The smallest number was " << min << ".\n";
	cout << "The total of the " << counter << " integers was " << sum << ".\n";

	return 0;
}

The only problem that I am having now is that if you insert a 1, 2, 3, and 4 into the program, it will show that the minimum number that you input is 0, even though you never input a 0. See below:

image.png.9c28da2793f186c80c6cf6bfd9ba63e8.png

This is happening because the "min" variable is set to 0 before the while loop, and the if statement that checks for the smallest number works by checking if the user inputted number is smaller than the "min" variable. I don't know a better way to do it... we aren't allowed to use arrays for some reason so I thought this would be the best way... The same happens to the max variable if you enter something like -1, -2, -3, and -4.

Any suggestions on a better way to check for the smallest and largest?

Link to post
Share on other sites

@SgtBot

First of all, printf and scanf are from the standard C library, not C++. One of the nice things about C++ is being able to get away from the clunky C stdio functions. I'd change to the stream method demonstrated above.

 

9 minutes ago, SgtBot said:

I found out I don't actually have to have the loop check for a char input to stop the program. It turns out that putting in an x or any other char will stop the program regardless.

You do have a loop that checks for a char input in some way:

11 minutes ago, SgtBot said:

 


	while (scanf("%d", &userInput) == 1) {
	//<snip>
	}

 

This will call scanf and execute the body code in a loop as long as the result of scanf is equal to 1. Scanf will return the number of items successfully extracted on success. You ask to extract a integer (%d). So, the loop will continue as long as scanf extracts 1 integer each time. Once you enter a character the extraction will fail and scanf will no longer return 1, exiting the loop.

 

18 minutes ago, SgtBot said:

The only problem that I am having now is that if you insert a 1, 2, 3, and 4 into the program, it will show that the minimum number that you input is 0, even though you never input a 0. See below:

image.png.9c28da2793f186c80c6cf6bfd9ba63e8.png

This is happening because the "min" variable is set to 0 before the while loop, and the if statement that checks for the smallest number works by checking if the user inputted number is smaller than the "min" variable. I don't know a better way to do it... we aren't allowed to use arrays for some reason so I thought this would be the best way... The same happens to the max variable if you enter something like -1, -2, -3, and -4.

Any suggestions on a better way to check for the smallest and largest?

The most obvious solution would be to use the 'counter' variable you already have. When a integer has been read and 'counter' is 0, meaning this is the first number that was read, assign the number you just read to both 'min' and 'max'. In all the next iterations, where 'counter' no longer equals 0, compare as you do now.

Link to post
Share on other sites

2 minutes ago, Unimportant said:

@SgtBot

First of all, printf and scanf are from the standard C library, not C++

Funny story actually... the class I'm taking is ANSI C, not C++... I'm just programming it in C++ and then translating it into the - as you said- "clunkier" C stdio stuff. (I'm doing this because I'm using the school windows machines in the library and then translating it when we have access to linux machines in class.)

5 minutes ago, Unimportant said:

@SgtBot

This will call scanf and execute the body code in a loop as long as the result of scanf is equal to 1.

I have a question about this actually.. why do you set the result equal to 1? I mean if I put in an 8 its not equal to 1 so shouldn't the loop stop? I've tried putting other numbers there instead of 1 and it always breaks it but I can't figure out why it has to be 1.

7 minutes ago, Unimportant said:

@SgtBot

The most obvious solution would be to use the 'counter' variable you already have. When a integer has been read and 'counter' is 0, meaning this is the first number that was read, assign the number you just read to both 'min' and 'max'. In all the next iterations, where 'counter' no longer equals 0, compare as you do now.

Okay I think I understand what you are saying... would I do something like this then?

if (counter == 0) {
min = userInput;
max = userInput;
}

 

Link to post
Share on other sites

2 minutes ago, SgtBot said:

I have a question about this actually.. why do you set the result equal to 1? I mean if I put in an 8 its not equal to 1 so shouldn't the loop stop? I've tried putting other numbers there instead of 1 and it always breaks it but I can't figure out why it has to be 1.

Because scanf returns the amount of items in the argument list that were successfully extracted. You only have 1 item in the argument list so the result can only be 1 (success) or 0 (failure).

 

You can put multiple items in the argument list for scanf:

float f;
int i;
scanf("%d %f", &i, &f);

This would attempt to extract 1 integer and 1 float. So scanf could return 2 (both extractions successful), 1 (only one extraction successful) or 0 (failure).

 

8 minutes ago, SgtBot said:

Okay I think I understand what you are saying... would I do something like this then?

almost, when counter does not equal 0 you need to apply the behavior you already had:

if (counter == 0) 
{
	min = userInput;
	max = userInput;
}
else
{
	if (userInput < min) 
	{
		min = userInput;
	}
	if (userInput > max) 
	{
		max = userInput;
	}      
}

 

Link to post
Share on other sites

1 hour ago, Unimportant said:

Because scanf returns the amount of items in the argument list that were successfully extracted. You only have 1 item in the argument list so the result can only be 1 (success) or 0 (failure).

 

You can put multiple items in the argument list for scanf:

This would attempt to extract 1 integer and 1 float. So scanf could return 2 (both extractions successful), 1 (only one extraction successful) or 0 (failure).

 

almost, when counter does not equal 0 you need to apply the behavior you already had:

Oh okay this is making a lot more sense now. So the %d in scanf checks for an integer, and the 1 is saying that the user should be giving only one input, and if the user enters a char, the loop condition returns false and stops the loop, which would mean if you tried to enter two separate numbers it would stop the loop as well right? Then for the first if loop it will set the min and max variables equal to only the first number you put in because after that the counter variable won't equal 0 anymore, and so it will go to the else part of the loop and check if the userInput was lower or higher than the input before it and adjust accordingly.

Link to post
Share on other sites

11 hours ago, SgtBot said:

which would mean if you tried to enter two separate numbers it would stop the loop as well right?

No. You only ask for a single integer each iteration of the loop, if the user enters two separate numbers only the first one will be extracted, the second one ignored and the function will still return 1.

 

11 hours ago, SgtBot said:

Then for the first if loop it will set the min and max variables equal to only the first number you put in because after that the counter variable won't equal 0 anymore, and so it will go to the else part of the loop and check if the userInput was lower or higher than the input before it and adjust accordingly.

Correct.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×