Possible to break a loop when outside of it? - c++

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.

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.

Making an if condition return if its true or while return if its true

When the condition is true or false, how can I make it return back and ask the question again, making the user re-enter the value?
Here is what I want to implement:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
int n;
cout<<"Enter numbers. Press 5 to stop: ";
cin>>n;
bool tr=true;
while(tr)
{
if(n!=5)
cout<<"You entered "<<n; //How to make it return again, since its false? I keep getting infinite loops :( ;
else
tr=false;
}
return 0;
}
You need to prompt the user in the while loop, so that it occurs in each iteration:
int n;
bool tr = true;
while(tr)
{
cout << "Enter numbers. Press 5 to stop: ";
cin >> n;
if(n!=5) {
cout << "You entered " << n;
} else {
tr = false;
}
}
Just put all your code (except 'n' and 'tr' definition) in while loop as follow:
int main()
{
int n;
bool tr=true;
while(tr)
{
cout<<"Enter numbers. Press 5 to stop: ";
cin>>n;
if(n!=5)
cout<<"You entered "<<n;
else
tr=false;
}
return 0;
}
The other answers all work, and there is something to be learned about improving program flow from them, but I believe the trick you're asking for is the continue keyword, which skips the remainder of this iteration of the loop.
bool tr = true;
int n;
while (tr)
{
cout << "Enter numbers...";
cin >> n;
if (n != 5)
continue;
else
tr = false;
}
EDIT Part 1: On the continue keyword.
You want to make your code as readable as possible. In this example, its use is unnecessary (as the other posters have shown); but it is the answer to the question "How do I skip the rest of processing in this iteration of my loop and continue to the next iteration?". Usually, such flow-breaking directives actually make code harder to read; but sometimes the opposite is true. Anything (or, at least, almost anything) that can be accomplished with continue or break, can be accomplished without them, so if you're going to use them, you want to have a definite reason for doing so. Usually, when I use continue, it's because I'm looping through a collection of inputs and I want to skip processing the loop whenever the input isn't in the format I'm expecting. Something like this (pseudo-code)...
foreach (Input i in ReceivedInputs)
{
if (i.isBad())
{
cout << "Bad input";
continue;
}
// Do massive block of calculating here.
}
is easier to read than this...
foreach (Input i in ReceivedInputs)
{
if (i.isBad())
cout << "Bad input";
else
{
// Do massive block of calculating here.
}
}
because the second version makes it harder to track what scope you're in, if you're looking toward the end of the massive block of calculating. In this case, I gain code readability by continue, so I use it. But simple code probably shouldn't use it. The break keyword is similar, though it's a lot easier to come up with examples where break is beneficial.
EDIT Part 2: On multiple iterations
This is just an issue of setting up the loop; there are no magic keywords here. The shortest way I can come up with, is probably something like this:
int n = 0;
int numberToTake = 10;
for ( int numbersTaken = 0; numbersTaken < numberToTake; ++numbersTaken)
{
cout << "Enter numbers...";
int n = 0;
for (cin >> n; n != 5; cin >> n)
cout << "Try again.";
// Do whatever processing on n you want to do here.
}
Though I should point out that, doing it this way, the only value you will ever get from the user will be 5, and if he inputs anything that doesn't fit in an integer, you will get unexpected behavior.
EDIT 3: After reading the comment more thoroughly, I think you're just looking for is the more traditional use of the for loop.
No need for the exra bool variable.
The idiom can be: Infinitely loop until the user enters 5:
for(;;) { // Loops infinitely
cout << "Enter numbers. Press 5 to stop: ";
cin >> n;
if(n == 5)
break; // Exits the loop
cout << "You entered " << n; // Before the if if you want to print 5 as well
}

A simple C++ While loop not working

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;

using user input such as YES and NO to control program flow in C++

I'm making a small program that uses a if else statement, but instead of using numbers to control the flow i want to be able to make the control work with with yes and no;
for example:
cout << "would you like to continue?" << endl;
cout << "\nYES or NO" << endl;
int input =0;
cin >> input;
string Yes = "YES";
string No = "NO";
if (input == no)
{
cout << "testone" << endl;
}
if (input == yes)
{
cout << "test two" << endl;
//the rest of the program goes here i guess?
}
else
{
cout << "you entered the wrong thing, start again" << endl;
//maybe some type of loop structure to go back
}
but I can't seem to get any variations of this to work, i could make the user type a 0 or 1 instead but that seems really stupid, i'd rather it be as natural as possible, users don't speak numbers do they?
also i need to be able to simply add more words, for example "no NO No noo no n" all would have to mean no
hopefully that makes some sense
also i would love to make this using a window but i've only learned basic c++ so far not even that and i cant find any good resources online about basic windows programming.
You're not reading in a string, you're reading in an int.
Try this:
string input;
instead of
int input = 0;
Also, C++ is case-sensitive, so you can't define a variable called Yes and then try to use it as yes. They need to be in the same case.
btw, your second if statement should be an else if, otherwise if you type in "NO" then it will still go into that last else block.
First of all, input must be std::string, not int.
Also, you've written yes and no wrong:
v
if (input == No)
// ..
// v
else if (input == Yes)
^^^^
If you want your program to work with "no no no ..", you could use std::string::find:
if( std::string::npos != input.find( "no" ) )
// ..
The same with "Yes".
Also, you could do this to be almost case-insensitive - transform the input to upper-case letters (or lower, whatever ), and then use find.This way, yEs will be still a valid answer.
bool yesno(char const* prompt, bool default_yes=true) {
using namespace std;
if (prompt && cin.tie()) {
*cin.tie() << prompt << (default_yes ? " [Yn] " : " [yN] ");
}
string line;
if (!getline(cin, line)) {
throw std::runtime_error("yesno: unexpected input error");
}
else if (line.size() == 0) {
return default_yes;
}
else {
return line[0] == 'Y' || line[0] == 'y';
}
}
string input;
cin >> input;
if (input == "yes"){
}
else if (input == "no"{
}
else {
//blah
}