A simple C++ While loop not working - c++

I have a simple while loop i'm trying to implement but for the life of me can't figure out what I'm missing. I have currentuser initialized at the top to -1
while(currentuser = -1){
cout << "Enter user ID: ";
cin >> id;
currentuser = search(a, length, id);
}
My search function is this:
int search (User a[ ], int length, string userID){
User u;
string tempid;
int templegnth; //I ignore length for now as I will use it later
for(int i=0; i<50; i++){
tempid = a[i].getID();
templegnth = tempid.length();
if((tempid == userID)){
return i;
}
}
return -1;
}
I know its something very simple but the answer escapes me right now.

The = (assignment) operator is not the same as the == (equality) operator.
The line :
while(currentuser = -1){
first assigns -1 to currentuser, and then checks if currentuser has a non-zero value. This will always be the case (-1 != 0), so the loop will never end.
You likely meant this instead :
while(currentuser == -1){
which compares currentuser to -1, and continues the loop as long as that comparison is true.

You need to change:
while(currentuser = -1){
to be:
while(currentuser == -1){
Currently you are assigning currentuser to -1 every time your loop runs, rather than checking if it is still assigned to that value.

Try == -1 instead of = -1

You've got the answers but here is a tip on how to avoid it in the future.
Always try to use
while(-1 == currentuser){
std::cout << "Enter user ID: ";
std::cin >> id;
currentuser = search(a, length, id);
}
as this way
while(-1 = currentuser){
;
}
will be thrown out by the compiler

Even with the = changed to ==, the loop still has problems.
while(currentuser == -1){
std::cout << "Enter user ID: ";
std::cin >> id;
currentuser = search(a, length, id);
}
Typing an EOT (control-D on a Linux box, control-Z? on windows) will raise std::cin's end of file condition. The value of id won't be changed, and the lookup will presumably keep on returning -1. The result is an infinite loop with lots of spew to std::cout.
One way to fix this is to break out of the loop when the std::cin >> id; fails. For example, if (! (std::cin >> id)) break;

Whenever I use a while loop and a boolean, I try to make sure it only runs if it is above or is 50 but instead whenever I execute a cout with the while and int, the outcome is a literal mess, its like the while loop executes a lot more than it should. Eg.
int Buses;
int People;
cin >> People;
while(People >= 50){
Buses += 1;
People -= 50;
};
cout << Buses << endl;
and when I input 757, my result was 32782.
Even by subtracting the int value by 32767, the values sort of fix itself but not the higher numbers, 99 is 1, 101 is 2 but c++ says that 300 is 3 although it is meant to be 6.
(My solution I found: I had to declare the Person and Buses variable with a 0 because the value was different without the starting 0.)
This is the fixed code:
int Buses = 0;
int People = 0;
cin >> People;
while(People >= 50){
Buses += 1;
People -= 50;
};
cout << Buses << endl;

Related

Console is being flooded when error checking for things that are not an int

I'm trying to only allow integer values into my program, so I've made the following function. The function is similar to other ones I've seen online, and mine seems to work just fine up until I add an ! in front of it to check if something is not an int.
Function to check if input is an integer:
bool isInteger(std::string s)
{
for (int i = 0; i < s.length(); i++)
{
if (isdigit(s[i]) == false)
{
return false;
}
return true;
}
}
Function being put to use:
int getLevel()
{
int level;
std::cout << "Level One\n";
std::cout << "Level Two\n";
std::cout << "Level Three\n";
std::cout << "Level Four\n";
std::cout << "Level Five\n";
std::cout << "Enter your level (1-5): ";
std::cin >> level;
while (!isInteger(std::to_string(level)) || level < 1 || level > 5)
{
std::cout << "Enter an integer value between 1-5 inclusive: ";
std::cin >> level;
}
clrscr();
return level;;
}
I believe the function works just fine until I put the ! in front of it. I am trying to only allow integer input into my program, and when I enter a double or string, the console becomes flooded with the message "Enter an integer value between 1-5 inclusive: " and doesn't give any time to enter an input. I am fairly new to c++ programming and could use some advice. Thank you!
std::cin >> level;
will try to read an integer and it will never read anything other than an integer. If this fails std::cin's failbit is set and further input operations (like std::cin >> level; inside the loop) are skipped.
You need to check if the reading succeeded and ignore the current input if not. Like this for example:
std::cout << "Enter your level (1-5): ";
while(!(std::cin >> level) || level < 1 || level > 5) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Enter an integer value between 1-5 inclusive: ";
}
As little semi-related hint: level will always be an integer. Converting it to a string will always be the string-representation of an integer, so isInteger(std::to_string(level)) will always be true, unless level is negative, because you don't check for the sign.
Also that return true; in isInteger must be outside the loop, else you only check the first character.
Thanks to all the replies and clarification, I've managed to come up with a solution of my own.
New isInteger function that now checks for everything that is needed including inputs like "0004" that a user suggested above:
bool errorCheck(std::string s)
{
int intLevel;
std::stringstream tempLvl(s);
tempLvl >> intLevel;
for (int i = 0; i < s.length(); i++)
{
if (isdigit(s[i]) == false || s[0] == '0' || intLevel < 1 || intLevel > 5)
{
return false;
}
}
return true;
}
The method in action:
std::cout << "Enter your level (1-5): ";
std::cin >> stringLevel;
while (!errorCheck(stringLevel))
{
std::cout << "Enter an integer value between 1-5 inclusive: ";
std::cin >> stringLevel;
}
std::stringstream lvl(stringLevel);
lvl >> level;
clrscr();
return level;
}
Please let me know if you spot any problems with the code or have any easier solutions. Thanks for all the help!
ok i am gonna tell u the fact that console input extracts the input from console so if u ever tried to do something like that
i.e read string in place of integer the cin is going to be in bad state you can check this fact by putting an if like this
if(!cin>>level) break;
and u will find it working actually stream takes input from the console and convert it to boolean value so u can always check it's state bad state return false else true...... ..
SO,finally the bug is in cin>>level...
I hope u understood.... also check out that return true statement..
i am gonna put u reference link for more answer on this bug...
user enters String instead of Int

How would I get this to repeat without getting stuck on invalid input?

quick question.
How would I get this code to loop itself so that it keeps asking the question, but still allow a different action when a non-numeric input is given?
int main()
{
int temp = 0;
while (temp =1, 10)
{
int amend_numb = -1;
cout << "\nWhich amendment? ";
cin >> amend_numb;
if (amend_numb == 1)
{
cout << "a.\n";
}
if (amend_numb == 2)
{
cout << "b.\n";
}
I attempted to put it into this while statement, however if I enter anything other than an integer into the cin, then it does an infinite loop of constantly repeating the cout statement. Is there any way to get rid of this problem?
while (temp =1, 10)
Although the expression is syntactically correct, it may not perform the way you think:
1. Assign temp to 1.
2. Disregard the value returned from the assignment (because of comma operator)
3. Remaining expression is 10, which is nonzero, so loop continues.
The general rule of thumb is to use a for loop for known quantities of iterations:
for (temp = 1; // assignment
temp < 10; // continuation expression
++temp) // iterator incrementing
{
// loop content
}
When interacting with Users, you want the loop to repeat until an exit condition is satisfied.
unsigned int temp = 0;
while (temp != 0)
{
cout << "Enter amendment number, 0 to quit: ";
cin >> temp;
if (temp > 0)
{
switch (temp)
{
//...
}
}
}
Some people like a forever loop with a break statement:
unsigned int temp = 0;
while (true)
{
cout << "Enter amendment number, 0 to quit: ";
cin >> temp;
if (temp == 0)
{
break; // terminate loop
}
switch(temp)
{
//...
}
}
while (true)
{
//your code
}
simple
and then for your none integer input, you should really do a type cast if you think the user might not provide expected input. Since cin would return a string so you should use string to int cast, something like "stoi" if your compiler supports it or look up c++ string to int I am pretty sure you will get bunch answers.
Edit: if the user might enter anything that is not a number, then you better check for error, put a try and catch statement between the cast, if it fails then tell the user input is not valid.

Problems with reading char input and with a loop counter

Ok so I am having a major issue here, and after spending two days on this, I can not find out why it is not working as I think it should.
First problem: I have a function to see if the player wished to play again by inputting a y or n. If they press n, it terminates as it should, but if they press Y or y it just asks them again if they want to play again, until any other char other than y is pushed that is.
My second issue, and the most annoying, is the loop counter I am using to determine if the char they entered as a guess was used or not in the word (hangman game). It worked before, after I made some minor changes, it no longer works as intended, and the butt of it is that I didn't mess with that code at all, it was elsewhere. Essentially, the loop counter is reset to 0 every time the loop encounters the user guess within the word, but if the counter equals the length of the word, that means that the user guess was not found, and it should set the display value to plus one. However, all it does NOW is stay at zero all the time, even if the user enters an incorrect guess, which should increment the display value by one, it remains at zero. I have spent two days trying to get JUST this part to work, and it WAS working yesterday, but not today, and I can use another set of eyes on it to see if I overlooked something!
void playHangman(string wordArray[], bool usedWords[])
{
string secretWord;
unsigned seed = time(0);
srand(seed);
int wordChoice = (rand()%20);
int counter = 0;
int display = 0;
bool winner = false;
int wordLength = secretWord.length();
int count;
char again;
do
{
while(usedWords[wordChoice])
{
if(wordChoice == 19)
wordChoice = 0;
else if(counter == 20)
{
for(int i = 0; i < SIZE; i++)
usedWords[i] = false;
wordChoice = (rand()%20);
counter = 0;
}
wordChoice++;
counter++;
}
secretWord = wordArray[wordChoice];
const char *word = new char [secretWord.length()];
word = secretWord.c_str();
char *userPrompt = new char [secretWord.length()];
for(int i = 0; i < secretWord.length(); i++)
userPrompt[i] = '_';
userPrompt[secretWord.length()] = '\0';
char userGuess = '\n';
while(!winner)
{
count = 0;
for(int i = 0; i < secretWord.length(); i++)
cout << userPrompt[i] << " ";
cout << "\n" << endl;
displayGallows(display);
if(display == 6)
{
cout << "Sorry, you lost!" << endl;
break;
}
cout << "Enter a letter: ";
cin >> userGuess;
cin.ignore();
for(int i = 0; i < secretWord.length(); i++)
{
if(word[i] == userGuess)
{
userPrompt[i] = userGuess;
count = 0;
}
else if(count == (wordLength - 1))
display++;
count++;
}
winner = checkWin(word, userPrompt, display, secretWord);
}
again = playAgain();
}while(again == 'Y' || again =='y');
}
char playAgain()
{
char playAgain;
cout << "Would you like to play again? Enter y or n: ";
cin >> playAgain;
return playAgain;
}
There are really two questions:
Why doesn't it restart a game? Answer: because the program thinks that the game was successfully played. You set up your variables in front of the loop and you don't reset them to play another game. Recommendation: create a function which actually plays the game and just call it from the outer loop. Play the game in that function.
Why doesn't it increment count? Dunno. Why you think count always stays at 0? However, it seems the condition count == (wordLength - 1) is unlikely to every become true because wordLength is set to the size of secretWord when secretWord happens to be empty (i.e. wordLength is set to 0) and never changed afterwards.
Asking to play again may be due to not resetting variable "winner". Doing as follows may correct it.
do
{
winner = false; //set to false at each iteration
while(usedWords[wordChoice])
{
if(wordChoice == 19)
wordChoice = 0;
else if(counter == 20)

I am trying to make a loop that will check if input is a number and if not ask again

So here is the code I have so far. I tried a few things like isDigit(nPlay) and !cin. Maybe I need a different loop. When I do either one, if I input a number more than 4 it acts like it is supposed too. But when I put in a letter or word then it goes into a infinite loop.
int view::numPlayer() {
int nPlay = 0;
while( nPlay == 0 ) {
cout << "How many players will there be?" << endl;
cin >> nPlay;
if(nPlay > 4 || nPlay < 2 || !cin) {
nPlay = 0;
}
system("CLS");
}
return nPlay;
It's because the failbit flag on std::cin, when set, isn't automatically cleared. That means the !cin will always be true. You have to clear the flag manually with the clear() function.
Rather than attempting to read an integer, then clear the stream's failbit if that failed, I'd read a string, and repeat if the conversion didn't succeed.
int value;
char *pos;
std::string temp;
cout << "How many players will there be?";
do {
std::getline(cin, temp);
nPlay = strtol(temp.c_str(), &pos, 10);
} while (*pos != '\0');

Possible to break a loop when outside of it?

After trying to make a while(bool) loop and it failing because I couldn't see the contents of the vectors because there was nothing in them, I made a while(true) loop with the intention of breaking out if the user inputs a 0. Here are the important portions of the code.
Edit: Working code, but what does|= mean?
#include "std_lib_facilities.h"
class Name_pairs
{
public:
vector<string>names;
vector<double>ages;
bool test();
string read_names();
double read_ages();
void print();
};
string Name_pairs::read_names()
{
string name;
cout << "Enter name: ";
cin >> name;
names.push_back(name);
return name;
}
double Name_pairs::read_ages()
{
double age;
cout << "Enter corresponding age: ";
cin >> age;
ages.push_back(age);
cout << endl;
return age;
}
void Name_pairs::print()
{
for(int i = 0; i < (names.size()-1) && i < (ages.size()-1); ++i)
cout << names[i] << " , " << ages[i] << endl;
}
bool Name_pairs::test()
{
if(ages.empty() || names.empty()) return true;
if(ages.back() = 0 || names.back() == "0"){
return false;}
return true;
}
int main()
{
Name_pairs np;
cout << "Enter names and ages. Use 0 to cancel.\n";
bool finished = false;
while(!finished){
finished |= "0" == np.read_names();
finished |= 0 == np.read_ages();}
np.print();
keep_window_open();
}
Well you could simply make each function return a bool, then in the loop check if the function returned false. If so break.
You could also throw an error from within the functions, catch it externally and handle it appropriately but I think this is a little extreme. I get the impression you are just looking for an 'exit code' type thing. If this is the case I would suggest simply returning a bool and checking whether you should break out of the loop.
Edit: So your updated code seems a little complicated, but this is what I was getting at as far as returning a bool goes:
void Name_pairs::read_names()
{
cout << "Enter name: ";
cin >> name;
names.push_back(name);
}
bool Name_pairs::read_ages()
{
cout << "Enter corresponding age: ";
cin >> age;
if ( age == 0 )
return false;
ages.push_back(age);
cout << endl;
return true;
}
// Now we can test if its time to break.
while ( true )
{
np.read_names();
if ( !np.read_ages() )
break;
}
If you change the problem and view it upside down it becomes quite simple.
Change your setter methods to actually return the value that was just entered. I also made age a local variable of the method to prevent side effects from creeping :
Double Name_pairs::read_ages()
{
Double age;
cout << "Enter corresponding age: ";
cin >> age;
ages.push_back(age);
cout << endl;
return age;
}
Then in the loop you can test directly for the returned value :
bool finished = false;
while(!finished)
{
finished = finished || "0" == np.read_names();
finished = finished || 0 == np.read_ages();
}
Since you are setting your exit condition in the main (type 0 to exit) it is preferable to test the exit condition there for consistency.
Is how I see it anyway... code is shorter and easier to understand
Edit I changed the code to reflects comments aem. This way the correct logical operator is used. As for the cascading evaluation it is quite true that if the first answer was 0 then the second question will not even be asked (finished evaluated to true thus the rest of the or statement will not be evaluated) and as such you must be careful of this (if for example you expect both Vectors to always have the same length). However I found that usability wise since the user already stated that he wanted to exit I saw no use in asking him the other question.
You could explicitly check in test() if ages/names are empty, and only do the "real" check if they are not:
bool Name_pairs::test() {
if (ages.empty() || names.empty())
return true;
return (ages.back() != 0) && (names.back() != "0");
}
You can have the functions return a value then check the value and break if necessary.
You could also just check the value that's been read in after you call the functions. In this case, it looks like doing if(names.back() == "something") or if(ages.back() == 0) would work.
EDIT:
Your general idea is fine(running test() on every iteration of the loop which returns false if your exit condition is met), but there are a couple implementation errors:
if(ages[bool_counter] = 0 || names[bool_counter] == "0")
You need "==" instead of "=" for the first condition. I bet your compiler warned you about this, you should generally listen to his warnings :). Your current statement is assigning 0 to ages[0] not checking it for being 0.
You should also check the size before attempting to dereference the first element, or you will, as you noted, get errors if ages or names are empty.
So changing that to
if( (ages.size() > 0 ) && (ages.back() == 0)) ||
(names.size() > 0) && (names.back() == "0"))
Should work, though I prefer deus's response for clarity.
"Break a loop when outside of it?" - this question doesn't make sense. If you're outside the loop, there's no need to break out of it, because you're already outside of it.
I suggest reading up on the basics, specifically "sequence" which is a shared common point of these types of languages.
http://javascript.about.com/library/blstruc1.htm
Then you can go on with loops - it's linked on the same page.
Now, this link describes Javascript, but the logic is essentially the same, and the coding style hardly differ at all from other C-type languages.
a |= b is a shorthand for a = a | b.
If either a or b is true, then a is true at the end.