conditional statement in while loop - c++

I must have missed something. I'm doing an exercise to learn c++ and it asks that if a user inputs either c,p,t or g character then carry on, otherwise re-request prompt, so I wrote this:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int main(void){
cout << "Please enter one of the following choices:" << endl;
cout << "c) carnivore\t\t\tp) pianist\n";
cout << "t) tree\t\t\t\tg) game\n";
char ch;
do{
cout << "Please enter a c, p, t, or g: ";
cin >> ch;
cout << "\"" << ch << "\"" << endl;
}while(ch != 'c' || ch != 'p' || ch != 't' || ch != 'g');
cout << "End" << endl;
cin.clear();
cin.ignore();
cin.get();
return 0;
}
This does not work and all I get is the prompt re-requesting it even when pressing either of the correct characters.
However if I change this line:
while(ch != 'c' || ch != 'p' || ch != 't' || ch != 'g');
to
while(ch != 'c' && ch != 'p' && ch != 't' && ch != 'g');
why is that? My understanding is that the "OR" statement should work as one of the tests is correct.

why is that? My understanding is that the "OR" statement should work as one of the tests is correct.
Exactly. There is always one of the tests that passes. A character will either be not 'c', or not 'p'. It can't be both 'c' and 'p'. So the condition is always true, leading to an infinite loop.
The alternative condition with the conjunctions works because it is false as soon as ch is equal to one of the alternatives: one of the inequalities is false, and thus the whole condition is false.

My understanding is that the "OR" statement should work as one of the tests is correct.
Well, you could use ||, but the expression would have to be:
while(!(ch == 'c' || ch == 'p' || ch == 't' || ch == 'g'));
By applying the De Morgan's law, the above simplifies to:
while(ch != 'c' && ch != 'p' && ch != 't' && ch != 'g');

Related

Unable to compare characters (c++)

I'm trying to make a simple mad libs program in c++, and i want to check and see if a word that a user entered starts with a vowel, and if it does, change the "a" before the word, to an "an". I've been able to get the first character stored, but it will not compare to the other characters in the If statement. Am i doing this completely wrong?
#include <string>
#include <iostream>
using namespace std;
int main() {
string adj_3;
string anN;
char firstChar;
// GETTING USER'S WORD
cout << "ADJECTIVE: " << endl;
getline(cin, adj_3);
// GETTING FIRST CHARACTER
firstChar = adj_3[0];
// SEEING IF IT'S A VOWEL (not working)
if(firstChar == ('a' || 'e' || 'i' || 'o' || 'u' || 'A' || 'E' || 'I' || 'O' || 'U')) {
anN = "n";
}
else {
cout << "not working" << endl;
}
cout << "I am having a" << anN << " " << adj_3 << " time at camp." << endl;
}
The || operator needs to be applied to two arguments, like so:
if (firstChar == 'a' || firstChar == 'e' || firstChar == 'i' || ...)
firstChar == 'a' evaluates to a boolean. firstChar == 'a' || firstChar == 'e' takes the two booleans that results from those two operations, and returns another boolean, which is then fed into the next || operation as the first argument. In this way you can "chain" the || operations until one of them is true, or until they're all false.
See here for examples and explanation.
hnefatl's answer is one way.
You can also use switch case without break statements to check vowel. Something like:
switch(firstChar)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U': cout<<"Vowel";
}
On top of that switch-case have many advantages over if-else ladder as stated here https://stackoverflow.com/a/1028463/6594779.
Logical operator || combines two boolean expressions, e.g. a==0 || b==1, and returns true if either of the two operands is true. If you pass a single character like 'a' as operand, this will be interpreted as true, since the value of 'a' is 97 and 97 != 0 => true. Hence, your expression ('a' || 'e' || 'i' || 'o' || 'u' || 'A' || 'E' || 'I' || 'O' || 'U') will always be true, and firstchar == (....) is the same as firstchar == true, which will probably give false.
You could write...
if (firstChar == 'a' || firstChar == 'e' || firstChar == 'i' || ...)
or...
if (strchr(firstChar, "aeiouAEIOU") != NULL)) ...
You can use an array too wherein you store all the vowels and then compare it. Something like shown below:
char vowels[10]={'a','e','i','o','u','A','E','I','O','U'};
int flag=0;
for(int i=0;i<10;i++)
{
if(vowels[i]==firstChar)
{
flag=1;
anN="n";
}
}
if(flag==1)
cout << "I am having a" << anN << " " << adj_3 << " time at camp." << endl;
else
cout << "not working" << endl;

Pig Latin - strings

So I am supposed to convert English words to Pig Latin using stringConvertToPigLatin(string word) function. All the answers I could find on the internet were using char[], and I am not allowed to do so.
The program is supposed to begin with adding -way if the first letter is a vowel, and adding -ay if it's a consonant. The problem is that it is always adding "-way", even if my "word" has no vowel at all. What am I doing wrong? This is my function:
string ConvertToPigLatin(string word)
{
char first = word.at(0);
cout << first << endl;
if (first == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U')
{
word.append("-way");
}
else
{
word.append("-ay");
}
return word;
}
As noted in the comments your if statement is wrong. Each comparison needs to be done individually. From the comment.
if (first == 'a' || first == 'A' || first == 'e' || ...)
However, rather than using a long if statement you should consider stuffing all of the vowels into a string and using find. Something like the code below will be easier to read and follow.
#include <iostream>
#include <string>
std::string ConvertToPigLatin(std::string word)
{
static const std::string vowels("aAeEiIoOuU");
char first = word.at(0);
std::cout << first << std::endl;
if (vowels.find(first) != std::string::npos)
{
word.append("-way");
}
else
{
word.append("-ay");
}
return word;
}
int main()
{
std::cout << ConvertToPigLatin("pig") << '\n';
std::cout << ConvertToPigLatin("alone") << '\n';
}
This outputs
p
pig-ay
a
alone-way
I'll explain why your code isn't working:
if (first == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U')
Let's walk through that iff statement using the word "Pig"
First the program checks first == 'a'... first == 'P' so that is false.
Then the program checks to see if false || 'A' is true. Since 'A' is true, false || 'A' is also true.
Short circuit evaluation kicks in, and the code doesn't bother checking the rest of the statement, the if condition is true so -way is appended.
To do what you want, you need to compare first to each letter. I.E.,
if (first == 'a' || first == 'A' || ...
Don't worry too much, this is a pretty standard mistake.

how to only allow 3 values in a "if" and "while" statement to allow the loop to exit

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.

Delimiter matching simple program won't work

I have looked over this for hours it seems like. This program will compile, it just can't detect errors correctly. And for some reason it will work when I type in hey [) or hey {], etc. But it won't work for hey[) or hey{]. Obviously in all cases it should detect an error but for some reason the space after 'hey' makes a difference.
#include<iostream>
#include <stack>
using namespace std;
bool delimiterMatching(char *file){
stack<char> x;
int count = 0;
char ch, onTop, check;
while(ch != '\0'){
ch = file[count];
if (ch == '(' || ch == '[' || ch == '{')
x.push(ch);
else if (ch == ')' || ch == ']' || ch == '}') {
onTop == x.top();
x.pop();
if((ch==')' && onTop!='(') || (ch==']' && onTop!='[') || (ch=='}' &&
onTop!= '{'))
return false;
}
count++;
}
if (x.empty())
return true;
else
return false;
}
int main()
{
char *test = new char();
cout << "enter sentence: ";
cin >> test;
if (delimiterMatching(test))
cout << "success" << endl;
else
cout << "error" << endl;
return 1;
}
With cin >> test you don't get a whole sentence, but only a string until cin encounters whitespace. So if you type (hey ), thest would be (hey and the closing brace would only be read by the next >>, whereas (hey) would work as expected.
You have a second issue with your test allocation, which might be too short for reasonable input.
Change main() as follows:
char *test = new char[256]; // enough space. COnsider also string
cout << "enter sentence: ";
cin.getline(test, 256); // full line input.
...
You have also two nasty bugs in delimiterMatching().
First you use an uninitialized ch in your while condition. Either initialise ch to a non nul char, or use while (file[count]).
And did you notice onTop == x.top(); ? Shouldn't it be onTop = x.top();?

Do While Loop Question

do
{
cout << "Car is coming ... " << "[P]ay or [N]ot?" << endl;
ch=getch();
} while ( ch !='q' || ch != 'Q');
Why will the code on top not work while the code below does? I tried it with parenthesis around each statement in numerous ways and the compiler would pop an error every time until I regrouped them as I did below. I'm just wondering why it does this.
do
{
cout << "Car is coming ... " << "[P]ay or [N]ot?" << endl;
ch=getch();
} while ( !(ch=='q' || ch=='Q') );
I'm using Visual Studio 2008 as my compiler; x86 architecture.
Learn De Morgan's laws
(not A) or (not B)
is not the same as
not (A or B).
(ch != 'q' || ch != 'Q') is always true: "ch is not equal to 'q' or ch is not equal to 'Q'".
The problem is your boolean logic is off and the two while conditions are not the same.
Top: Character is not 'q' or is not 'Q'
Bottom: Character is not ('q' or 'Q')
The Top will return true for every single character possible. The bottom will return true for every character except 'q' and 'Q'
I think you want this in your first example:
ch !='q' && ch != 'Q'
You want that the input is not q AND not Q.
!(ch=='q' || ch=='Q') is equivalent to ch!='q' && ch!='Q'. See also De Morgan's laws.
You've got the logic backwards, that's my negating it works. By DeMirgan's laws, !(ch == 'Q' || ch == 'q') is the same as ch != 'Q' && ch != 'q'.
Since a if it cannot be both little q and big Q at the same time, while (ch != 'Q' || ch != 'q') doesn't make sense because if it is 'Q' then it won't be 'q', and vice versa.
When inverting all your logic using '!', you did right by reversing the conditional operators "==" to "!=", but you forgot to reverse the logical operators "||" to "&&". Thus, this should be correct:
while (ch!='q' && ch!='Q');
I use C#, so while code above will work, I would have used this instead as it is easier to read:
while (ch.ToUpper() != 'Q');