While not equal statement and or differences - c++

while ((choice != "Wizard") && (choice != "Knight"))
This is the only one that worked
while ((choice != "Wizard") || (choice != "Knight"))
while (choice != "Wizard" || "Knight")
Honestly, I don't understand why using OR won't work and what difference it has when I separate them. Hoping someone can help explain.

Take the string "Wizard":
Does it differ from "Wizard"? No.
Does it differ rom "Knight"? Yes.
So "different from Wizard AND different from Knight" is false (it does not differ from "Wizard"). However, "different from Wizard OR different from Knight" is true (it does differ from "Knight").
As for the third form, choice != "Wizard" || "Knight" is parsed as (choice != "Wizard") || "Knight". "Knight" is a string literal and as such, it decays to a non-null pointer in most expressions. Being non-null, the pointer converts to true. So you're effectively asking: "choice differs from "Wizard" OR true." That is of course always true.

As an alternative to an ever-growing chain of (choice != "...") &&, you can instead create a container of things to test for, and see if choice is an element of that container.
static const std::unordered_set<std::string> options = {
"Wizard",
"Knight",
"Rogue",
"Basket Weaver",
};
while (options.count(choice) == 0)

Related

Optimized code for two string compare in if condition

I want to do two string compare and used two different if condition. Is there any better way to do string compare in one if condition
if (strcmp(Buff1(), Config1) == 0)
{
if (strcmp(Buff2, Config2) == 0)
{
// my code goes here
}
}
The equivalent code is:
if ((strcmp(Buff1(), Config1) == 0)) &&
(strcmp(Buff2, Config2) == 0))
{
// my code goes here
}
Note: The compiler should generate the same machine code for both code samples. The difference is cosmetic and primarily aimed at the reader of the code.
You do get a difference when you add else clauses:
if (strcmp(Buff1(), Config1) == 0)
{
if (strcmp(Buff2, Config2) == 0)
{
// my code goes here
}
else
{
// else 1
}
}
else
{
// else 2
}
Compared to:
if ((strcmp(Buff1(), Config1) == 0)) &&
(strcmp(Buff2, Config2) == 0))
{
// my code goes here
}
else
{
// Single else clause
}
In addition to Klas's answer(just in case you're not familiar with the AND operator) - the AND operator ('&&') checks the first condition and it continues to check the second condition -only if- the first condition is true.
So in your specific question, it checks if the first couple of strings are equal and only if true (are equal), it checks if the second couple are also equal.
The obvious optimization (not mentioned yet), if you know anything about those strings, is to first perform the compare that is more likely to fail.

C++ setGender method reverts to default values

I've written the code bits below. I have a constructor which takes five arguments. Unfortunately, the setGender method spits out a default 'M' for all instances of a class rather than setting the gender to the specified parameter. What am I doing incorrectly? Any advice would be greatly appreciated. Thank you.
DateProfile::DateProfile(char gdr,
char searchGdr, int romanceScale, int financeScale, string theName)
bool DateProfile::setGender(char gdr)
{
if (gdr != 'M' || gdr != 'F')
return false;
gender = gdr;
return true;
}
if (gdr != 'M' || gdr != 'F') is always true, irrespective of input. If you're passing 'M', the second part of the expression is true. If you're passing anything else, the first part of the expression becomes true.
What you meant to write is if (gdr != 'M' && gdr != 'F') instead.
Increasing the warning level of your compiler may have helped you spot the error. Most compilers will warn about expressions always evaluating to a single value, or at least about the unreachable code following it.

C++ const char if-statement

So I'm trying to get this program that will say good or bad depending on your answer and I didn't want to have a really long if and else if statement with a bunch of strings so I put a bunch of possible answers in two chars and I want it to answer depending on what you say. The program only replies to the good answers saying good even if you enter in one of the bad answers.
const char* good[5] = {
"good", "great", "amazing", "amazing!", "fantastic"
};
const char* bad[5] = {
"bad", "bad pal", "bad eugene", "not good", "not good pal"
};
string input01 = "";
int main() {
cout << "Hello" << endl;
system("PAUSE");
system("CLS");
cout << "How are you doing today?" << endl;
cin >> input01;
transform(input01.begin(), input01.end(), input01.begin(), ::tolower);
if (input01 == good[0 > 5] || good[0 < 5]){
system("CLS");
cout << "good" << endl;
system("pause");
}
else if (input01 == bad[0 > 5] || bad[0 < 5]){
system("CLS");
cout << "bad" << endl;
system("pause");
}
}
This: if (input01 == good[0 > 5] || good[0 < 5]) probably doesn't do what you expect (because I can't imagine wanting what it really does).
0 > 5 is evaluated as a test of whether 0 is greater than 5. Since it's obviously not, that produces false. Since it's being used in a context where an integer is needed, that's converted to 0, so that part of the expression becomes if (input01 == good[0].
Likewise, 0 < 5 tests whether 0 is less than 5 (which it obviously is) so the result is true, which converts to 1, so that part of the expression is good[1]. Since that in turn is being used as a Boolean expression, it's treated as equivalent to good[1] != 0.
So what you have overall is if (input01 == good[0] || good[1] != 0).
That seems close enough to useless that I'm pretty sure it's not what you wanted. In particular, good[1] is a pointer. A pointer will compare equal to 0 if and only if it's a null pointer. Since it's initialized to point at something, it's not a null pointer, so that part of the expression will always evaluated as true.
of course, your other if statement is about equally useless.
If you want to check whether input01 is equal to any of the items in good, you might (for one example) use std::find:
if (std::find(std::begin(good), std::end(good), input01) == std::end(good))
// input01 was not present in `good`.
To make that work correctly, you'll want to use std::strings though:
std::vector<std::string> good{"good", "great", "amazing", "amazing!", "fantastic"};
It's kind of pointless for only 5 items, but if you lists of good and bad words are likely to get really large, you'd probably be better off sorting them, then using std::binary_search, or else using std::unordered_set instead.
Try:
if ((strcmp(input.c_str(), good[0]) == 0) ||
(strcmp(input.c_str(), good[1]) == 0) ||
...
(strcmp(input.c_str(), good[4]) == 0))
Or better switch the keywords to strings,
const string good[5] = {
"good", "great", "amazing", "amazing!", "fantastic"
};
and then
if ((input == good[0]) ||
(input == good[1]) ||
...
(input == good[4]))
Or even better, pack the keywords into a set
const set<string> good{"good", "great", "amazing", "amazing!", "fantastic"};
and then
if (good.find(input) != good.end())
Why don't you just check if the input01 is in your array. You should be able to use the find() function to do this. Something like
if(std::find(std::begin(good), std::end(good), input01) != std::end(good))){do something}
You may not need the std:: references

Issue with for loop, it reads both if and else if statement

I have an issue with my for loop. It goes through two arrays and compares the account number and PIN. An if statement checks if the combination of account number and PIN are correct. Since I changed this part (user_Account != accounts[i] || user_Pin != pins[i]) from the original (user_Account == accounts[i] && user_Pin != pins[i]), this happens. Before that it worked perfectly, but I was afraid that if someone types wrong account, then the program might crash so I made that change. Here is part of the code, I can post more if needed. Please have one thing in mind I am in beginning class, so no advanced changes or recommendations, I need something on my current level. I appreciate any help.
for (int i = 0; i < 6; i++)
{
if(user_Account == accounts[i] && user_Pin == pins[i])
{
cout << "You entered correct combination of account and pin number." << endl;
}
else if(user_Account != accounts[i] || user_Pin != pins[i])
{
cout << "You entered wrong account and/or wrong pin number. Please start over." << endl;
return 0;
}
}
When you converted from
(user_Account == accounts[i] && user_Pin != pins[i])
to
(user_Account != accounts[i] || user_Pin != pins[i])
you should have converted to:
(user_Account != accounts[i] || user_Pin == pins[i])
You are actually applying something called De Morgan's laws, and it's worth reading up on them for the history at least :).
Regarding if you should have separate if-else clauses for account fail compared to PIN fail - that's kind of a design decision. If someone was trying to break into your 'bank' and was guessing both the PIN and the account number from, say, looking over someone's shoulder, then seperate error messages would help him/her find the correct combination more quickly. On the other hand, if (more likely) a customer has just make a typing error, it's nice to have a message telling them. It's pretty much up to you.
If there are only two cases:
Both account id and password match
or
At least one doesn't match
I would just save yourself the headache of a second condition and let the check be this:
if (user_Account == accounts[i] && user_Pin == pins[i])
// accounts match message
else
// accounts don't match message
Also, a pointer on your for loop: you might want to make sure the for loop doesn't keep going when one of the arrays runs out, so your for loop signature could be this:
for (int i = 0; (i < accounts::size) && (i < pins::size); i++)

Logical error with the || operator?

A part of my program (I can add more details if necessary) contains this line:
if((e->start->explored = false) || (e->end->explored = false)){
//do action...
}
This is part of a graph algorithm, where e is a directed edge with incident vertices "start" and "end." I would like the 'action' to happen if at least one of the incident vertices of e is unexplored, but this logic appears to be faulty. Although I used a small example and verified that, indeed, the start and end vertices of my edges were unexplored to start with, my overall function is going into an infinite loop.
So then I tested it like this:
if((e->start->explored = false) || (e->end->explored = false)){
//do action...
}
else cout << "FAIL";
...and, of course, it printed a screen of "FAIL." What is my logic error here?
You're assigning false to your properties instead of testing them against false. This is a mistake often made, and quite hard to debug. Change your = assignment operator to the equality operator ==:
if((e->start->explored == false) || (e->end->explored == false)) {
// Do action...
} else {
cout << "FAIL";
}
Instead of comparing the values to false, it's clearer to use the ! not operator instead. The inner brackets are done away with, too:
if(!e->start->explored || !e->end->explored) {
// Do action...
} else {
cout << "FAIL";
}
As the others have expounded you accidentally used assignment instead of comparison. However, the real solution is not to compare at all:
Comparing bool values to literals true and false is nonsensical!
Instead, write:
if(! e->start->explored || ! e->end->explored)
You have used the assignment operator = not the comparison operator ==.
You are assigning values here:
if((e->start->explored = false) || (e->end->explored = false)){
Should be:
if((e->start->explored == false) || (e->end->explored == false)){