I'm making a small program for myself and any of my friends at school to use. I have a function (C++), called getChoice(), that returns a choice that the user made:
std::string getChoice(const std::string& s)
{
std::string choice;
if (s == "sp")
{
do
{
std::cout << "Do you want to search for a video or play it? (s/p): ";
std::cin >> choice;
if (choice[0] == 'S' || choice[0] == 'P')
choice[0] = tolower(choice[0]);
} while (choice.compare("s") != 0 || choice.compare("p") != 0);
}
else if (s == "vidtype")
{
do
{
std::cout << "Do you want to use vine or yt? (vine/yt): ";
std::cin >> choice;
} while (choice.compare("vine") != 0 || choice.compare("yt") != 0);
}
else
{
std::cout << "Uh, this function only supports \"sp\" and \"vidtype\"\n\n";
exit(EXIT_FAILURE);
}
return choice;
}
My issue is that the program gets stuck in an infinite loop at
"Do you want to search for a video or play it? (s/p): ";
I've rewritten the entire program, and that didn't fix it. I've looked up on using !=; it seems that I should use std::string.compare().
And I also tried outputting choice after using std::cin. It looks just fine in console output, showing s and p, but the tests in the do-while both fail somehow. Is there something I'm missing here?
while (choice.compare("s") != 0 || choice.compare("p") != 0);
If not S or not P:
If you input S, not P will evaluate to true, this continuing the loops
If you input P, not S will evaluate to true, this continuing the loops
If you input anything other than S or P, both will be true, this continuing the loop.
You probably meant to do:
while (choice.compare("s") != 0 && choice.compare("p") != 0);
If not S and not P (aka some other character besides S and P).
This incorrect logic is also present in your second loop (thank you dwcanillas)
while (choice.compare("vine") != 0 || choice.compare("yt") != 0);
Change the condition in the while loop the following way
do
{
std::cout << "Do you want to search for a video or play it? (s/p): ";
std::cin >> choice;
if (choice[0] == 'S' || choice[0] == 'P')
choice[0] = tolower(choice[0]);
} while (choice.compare("s") != 0 && choice.compare("p") != 0);
It is easier to consider the negation of the condition when the loop has to be terminated. For example
!(choice.compare("s") != 0 && choice.compare("p") != 0)
or more visually
not (choice.compare("s") != 0 && choice.compare("p") != 0)
is equivalent to
choice.compare("s") == 0 || choice.compare("p") == 0
So when the user entered either "s" or "p" then exit the loop.
The problem is the line
while (choice.compare("s") != 0 || choice.compare("p") != 0);
If you change the logic to
while (choice.compare("s") == 0 || choice.compare("p") == 0);
it will be good.
Related
I am a beginner at c++ programming and I am supposed to create a program in which answers that does not meet certain conditions would produce certain statements.
I also added
cin.ignore(INT_MAX, '\n');
in order to use
getline
and
cin
together. However, I think I may have misunderstood the nature of how they work and I used
cin.ignore(INT_MAX, '\n')
before using the first getline function, and it was causing my program to pause. I think that I am supposed to use this only if i use cin before, and when I want to use a getline function in order to prevent the getline function from taking in the empty space?
at the start, and it is causing me errors, I'm not sure when I use this.
I think this part might be the error... but I'm not quite for how the || and the && operators work
else if (donorGender != "Male" || "Female" || "Trans Male" || "Trans Female" || "Queer" || "Different")
is this it the way I do it?
else if (donorGender != "Male" && donorGender != "Female" && donorGender != "Trans Male" && donorGender != "Trans Female" && donorGender != "Queer" && donorGender != "Different")
or is this the way I do it
Please help...
The statement
cin.ignore(INT_MAX, '\n');
is pausing your program at the start until you press Enter key.
From this:
std::istream::ignore
istream& ignore (streamsize n = 1, int delim = EOF);
Extract and discard characters
Extracts characters from the input sequence and discards them, until either n characters have been extracted, or one compares equal to delim.
Generally, cin.ignore(INT_MAX, '\n') used with getline if you have some other input statements using cin before calling getline because when a user inputs something with cin, they hit Enter key and a \n (newline) character gets into the input buffer. Then if your program calling getline, it gets the newline character instead of the string you want. In your program you are is using getline for the first input from the user, so you don't need it. You can safely remove cin.ignore statement from your program.
This statement is wrong:
else if (donorGender != "Male" || "Female" || "Trans Male" || "Trans Female" || "Queer" || "Different")
You need to compare donorGender with all the possible valid values and not only with just one valid value. Even if you compare donorGender != with all valid values this will not work because || operator in the condition will always evaluate to true as a valid value of donorGender will be != rest of all valid values. Change it to:
else if (donorGender != "Male" && donorGender != "Female" && donorGender != "Trans Male" && donorGender != "Trans Female" && donorGender != "Queer" && donorGender != "Different")
With these changes, your program should work as expected.
Also, I would suggest you to add some input validation for all the inputs you are taking from the user.
Your code says that it will test donorName else donorGender and so on. You need to check all the conditions. and your donorGender checking if statement is not correctly formatted. What if user enters both name and gender invalid!
I think you should not check other conditions if one if false. if you want to tell all the wrong things then approach is different. but in your case below code can help. try it out!
Nested Conditional Statements
if(donorName != "")
{
if(donorGender == "Male"
or donorGender == "Female"
or donorGender == "Trans Male"
or donorGender == "Trans Female"
or donorGender == "Queer"
or donorGender =="Different")
{
if(donorAge >= 0) {
if(donorWeight >= 0) {
if (donorHeight >= 0)
{
cout << "--- You must enter a valid height." << endl;
return (-1);
}
else {
}
}
else {
cout << "--- You must enter a valid weight." << endl;
return (-1);
}
}
else {
cout << "--- You must enter a valid age." << endl;
return (-1);
}
}
else {
cout << "--- You must enter a valid gender." << endl;
return(-1);
}
}
else {
cout << " --- You must enter a valid name." << endl;
return (-1);
}
I'm trying to make a program that will run over and over again, provided the user says yes every time. Unfortunately, it doesn't seem to recognize when I input yes or no into it, and always does the default "Come again?" message. This is the code I'm using to get the input from the console:
bool getYN(){
bool confirmed = 0;
bool answer = 0;
string input;
while(!confirmed){
getline(cin, input, '\n');
transform(input.begin(), input.end(), input.begin(), toupper);
if(input.c_str() == "Y" || input.c_str() == "YES"){ //If the user says yes
confirmed = 1;
answer = 1;
} else if(input.c_str() == "N" || input.c_str() == "NO"){ //If the user says no
confirmed = 1;
answer = 0;
} else { //If the user says something else entirely
printf("\nCome again? (Y/N) ");
};
};
return answer;
};
I have included <string> and <algorithm>. For some reason, it always acts like it's not getting y/yes or n/no when I type them in. It just keeps asking me to answer again.
if(input.c_str() == "Y" || input.c_str() == "YES"){ //If the user says yes
confirmed = 1;
answer = 1;
} else if(input.c_str() == "N" || input.c_str() == "NO"){ //If the user says no
confirmed = 1;
answer = 0;
}
You should not be doing c-string comparisons like this. You're taking the address of a char and comparing against the address of a text-allocated object. Of course the comparison is going to return false.
With c++ strings, simple operator== comparisons are valid:
if(input == "Y" || input == "YES"){ //If the user says yes
confirmed = 1;
answer = 1;
} else if(input == "N" || input == "NO"){ //If the user says no
confirmed = 1;
answer = 0;
}
#include <iostream>
#include <string>
using namespace std; // For speed
int main()
{
bool saidYes = false;
string input;
while (!saidYes)
{
cout << "Input yes or no: ";
getline(cin, input);
if (input == "no" || input == "n" || input == "NO")
{
saidYes = true; // breaks the loop
}
if (input == "y" || input == "Y" || input == "yes" || input == "YES")
{
saidYes = false;
}
}
return 0;
}
You can use the above example to eliminate a huge portion of unnecessary code, I chose not to add the else statement but it will work if you add that here as well.
You can also condense this code even further but this was only intended to be a simple example as to how to better get this working for you!
As it was said above you can use == to compare the strings, if you're coming from certain other languages it can be an annoying change to get used to lol.
I have included string and algorithm. For some reason, it always acts like it's not getting y/yes or n/no when I type them in. It just keeps asking me to answer again.
algorithm is not required for what you're trying to do, and your making the reading and acceptance of the string input much more difficult than it needs to be.
If you look above you'll see the string input; This is going to be your variable that you can use to store the user input string into.
You'll also notice getline(cin, input); This is what you can use to "read" the string that the user enters when they're prompted to.
#Kelvin Shadewing My initial answer was only directed at your Question, this next example is directed to your comment to me below!
So you've got quite a few options but assuming that you want the user to input either yes or no and depending on the input you want to produce a specific result while ensuring that the user is prompted over and over again to input either yes or no all you have to is modify my original answer like so.
#include <iostream>
#include <string>
using namespace std; // For speed
int main()
{
bool saidYes = false;
string input;
while (!saidYes)
{
cout << "Input yes or no: ";
getline(cin, input);
if (input == "no" || input == "n" || input == "NO")
{
saidYes = true;
cout << "you said no" << endl;
/* breaks the loop by changing the
bool (true or false flag) to true, if you want to produce a specific result,
whether it's a simple output statement or a function call you can put it here
*/
}
else if (input == "y" || input == "Y" || input == "yes" || input == "YES")
{
saidYes = true;
cout << "You said yes" << endl;
/* breaks the loop by changing the
bool (true or false flag) to true, if you want to produce a specific result,
whether it's a simple output statement or a function call you can put it here
*/
}
else saidYes = false;
}
return 0;
}
I've modified my code based on the current best answer, but I've also optimized it so that confirmed is no longer necessary.
bool getYN(){
bool answer = 0;
string input;
while(!answer){
getline(cin, input, '\n');
transform(input.begin(), input.end(), input.begin(), toupper);
if(input == "Y" || input == "YES"){
answer = 2;
} else if(input == "N" || input == "NO"){
answer = 1;
} else {
printf("\nCome again? (Y/N) ");
};
};
return answer - 1;
};
Small optimization, sure, but every little bit counts.
I'm just stuck on some logic statements.
specifically the ones that are in the function char GetInteger() so how would I only allow 3 values to cause the loop to exit.
char GetInteger( /* out */ char& usrinput)
{
do
{
cin >> usrinput;
cin.ignore(200,'\n');
if (usrinput != 0 || usrinput != 1 || usrinput != 2)
{
cout << "Invalid Input." << userinput << " Try Again\n";
}
} while(usrinput != 0 || usrinput != 1 || usrinput != 2);
return userInput;
}
Two issues with this code:
First userinput has a type of char. So when you read from a stream you read a single character (after dropping white space). So when a user types 1<enter> you get the character '1' in the variable userinput. Note the character '1' is not the same as the number 1.
Thus your test should be:
userinput != '1';
Secondly your boolean logic is wrong. When first learning it is sometimes easier to state the problem as a list of values that you would like to be acceptable (not the unacceptable ones).
You want the conditions to be false if the userInput has one of your accepted values (any good value will fail the test and thus not invoke the bad code). The first step to this is to get a true if any of your values are valid.
// If any value is good then true.
userinput == '1' || userinput == '2' || userinput == '3'
To invert this just add a not to the expression.
if (! (userinput == '1' || userinput == '2' || userinput == '3') )
Note: in boolean logic
!(A || B) => (!A && !B)
So you could re-write the above as:
if (userinput != '1' && userinput != '2' && userinput != '3')
I think this was your main mistake you converted the == into != but did not convert the || into &&.
I would also suggest that you could simplify this (as you may get more valid result) byconverting this into a range based test.
if (userinput < '1' || userinput > '3')
{
// Test Failed.
}
Additionally. Since you have the test in two places. You should yank it outinto its own function. Then you can call the function to do the test.
bool isUserInputValid(char userInput)
{
return userInput >= '1' && userInput <= '3';
}
Now we can re-write your original function as:
char GetInteger( /* out */ char& usrinput)
{
do
{
cin >> usrinput;
cin.ignore(200,'\n');
if (!isUserInputValid(userinput))
{
cout << "Invalid Input." << userinput << " Try Again\n";
}
} while(!isUserInputValid(userinput));
return userInput;
}
First of all, you should use int instead of string as you are reading integer.
You can use while(1) instead of putting condition in while. Inside while loop, if your selection is 0 or 1 or 2, you can simply break the loop.
When I enter start then the program outputs the else function even though I fulfilled the criteria, I have tried with && as well and it still didn't work. Any answers would be appreciated.
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main ()
{
float timer;
bool end;
std::string input;
end = false;
cout << "Enter start then a number to count down from" << ".\n";
while (end == false){
cin >> input;
if (input.find("end" || "End") != std::string::npos)
end = true;
else if (input.find("start" || "restart" || "Start" || "Restart") != std::string::npos)
{
cin >> timer;
while (timer>0){
timer -= 0.1;
Sleep(100);
cout << timer << ".\n";
}
cout << "Finished! Enter restart then another number to perform another countdown, or enter end to close the program" << ".\n";
}
else
cout << "Enter start" << ".\n";
}
return 0;
}
Replace
if (input.find("end" || "End") != std::string::npos)
with:
if (input.find("end") != std::string::npos || input.find("End") != std::string::npos)
Similarly for your other if.
It seems obvious what your expression means, but when you break it down it really doesn't make sense. find expects a string, and "end" || "End" is not a string.
the Logical or operator, || only works in boolean expressions.
For instance, if you had
bool A = true
bool B = false
bool C = A||B;
than you will have set bool C to be True. IT just takes 2 booleans, and returns true if either of those booleans is true. That's all logical or does.
You might want to try something like
if (input.find("end") != std::string::npos || input.find("End") != std::string::npos)
The || works only in logical boolean expression.
From the standard (emphasis is mine):
5.15 Logical OR operator [expr.log.or]
The || operator groups left-to-right. The operands are both contextually converted to bool (Clause 4). It returns true if either of its operands is true, and false otherwise.
So in input.find("end" || "End"), it tries to convert "end" and "End" to bool. And the operator || will return a bool also.
Here to solve your problem you need to replace:
if (input.find("end" || "End") != std::string::npos)
by
if ( input.find("End") != std::string::npos ||
input.find("End") != std::string::npos )
And do the same in the second find.
C++ simply doesn't work that way. When you write
input.find("end" || "End") != std::string::npos
the compiler sees the logical or on two non-null const char pointers, which results in the boolean value true. This is then interpreted as a char with the value 1 ('\1') which is then searched in the string - certainly not what you intended. If you want to know if you string is in a set of strings, you could use:
static std::set<std::string> s = { "end", "End" };
s.find( input ) != s.end();
While maybe not the most efficient code in the world, but with a C++11 compiler you can also condense it into a single line like this:
if( std::set<std::string>{ "end", "End" }.count( input ) ) {
// found...
}
if (input.find("end" || "End") != std::string::npos)
// ^^^^^^^^^^^^^^
The || operator is not being used correctly here. The righthand expression will return true because it is non-zero, then it will be returned. So the statement resolves to input.find("end"). You need to use two separate conditional statements there:
if (input.find("end") != std::string::npos ||
input.find("End") != std::string::npos)
I'd recommend using regex instead for things like that:
regex
The argument of the function call
input.find("end" || "End")
has type bool and means that addess of string literal "end" or/and address of string literal "End" is not equal to zero. It is obvious that the both string literals have addresses that are not equal to zero. So the call is equivalent to
input.find(true)
The compiler finds an overloaded function find that is the most suitable for this argument. This function is
find( charT, c, size_tipe pos = 0 );
Value true is implicitly converted to value charT( 1 ) and the function tries to find char with value 1 in your string.
here is a fix:
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main()
{
float timer;
bool end;
std::string input;
end = false;
cout << "Enter start then a number to count down from" << ".\n";
while (end == false) {
cin >> input;
if (input.find("end") != std::string::npos | input.find("End") != std::string::npos)
end = true;
else if (input.find("start") != std::string::npos | input.find("Start") != std::string::npos | input.find("restart") != std::string::npos | input.find("Restart") != std::string::npos)
{
cin >> timer;
while (timer > 0) {
timer -= 0.1;
Sleep(100);
cout << timer << ".\n";
}
cout << "Finished! Enter restart then another number to perform another countdown, or enter end to close the program" << ".\n";
}
else
cout << "Enter start" << ".\n";
}
return 0;
}
it should be like this if (input.find("end") != std::string::npos | input.find("End")!= std::string::npos or this if (input.find("end") != std::string::npos || input.find("End")!= std::string::nposinstead of if (input.find("end" || "End") != std::string::npos)you can use logical or or bitewise or.
I wish to achieve to limit user on only 0 or 1 when program asking for boolean variable.
I'we tried to do so, but it doesn't work. It still keep asking me for typing in.
bool ele;
do{
cout << "Elektro:\t";
cin >> ele;
if (cin && ele == 0 && ele == 1) break;
cin.clear();
cout << "Neveljaven vnos!" << endl;
}while(true);
The good news is, that operator>> for bool by default allows only '0' or '1' as valid input. That means you don't need to explicitly check the value after read - if stream state is ok, so is your bool:
bool ele;
if (!(cin >> ele)) {
// error;
}
The reason you're getting an infinite loop when you enter something like "cvdsavd" is that you only clear the error flags, but don't get rid of the bad charaters. So your loop keeps trying but never can get a valid input. You need to get rid of the garbage:
bool ele;
while (!(std::cin >> ele)) {
std::cout << "Neveljaven vnos!\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Reference for ignore(). You also need to include <limits> for numeric_limits template.
Lp :)
As chris points out, you want to do if (cin && (ele == 0 || ele == 1)) break;
You cant do that :
if (cin && ele == 0 && ele == 1) break;
because its always false because ele cant be in same time 1 or 0 ... It can be only one of this figures.
if(ele == 0 || ele == 1) break;