Double negative IF statements - if-statement

While reviewing code, I have come across a few if staments using ! followed by an != in the assessment e.g.
if (!(fs.ReadByte() != (byte)'D' ||
fs.ReadByte() != (byte)'I' ||
fs.ReadByte() != (byte)'C' ||
fs.ReadByte() != (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
Is there any reason to use a double negative over assessing positive e.g.
if ((fs.ReadByte() == (byte)'D' ||
fs.ReadByte() == (byte)'I' ||
fs.ReadByte() == (byte)'C' ||
fs.ReadByte() == (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
Thanks

Those two are different. The first says "None of these are not equal", the second says "any of these are equal".
If you applied the ! operator across them, you'd have to change the || to an &&:
if ((fs.ReadByte() == (byte)'D' &&
fs.ReadByte() == (byte)'I' &&
fs.ReadByte() == (byte)'C' &&
fs.ReadByte() == (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}

Related

iterate char by char through vector of strings

I want to iterate char by char in a vector of strings. In my code I created a nested loop to iterate over the string, but somehow I get an out of range vector.
void splitVowFromCons(std::vector<std::string>& userData, std::vector<std::string>& allCons, std::vector<std::string>& allVows){
for ( int q = 0; q < userData.size(); q++){
std::string userDataCheck = userData.at(q);
for ( int r = 0; r < userDataCheck.size(); r++){
if ((userDataCheck.at(r) == 'a') || (userDataCheck.at(r) == 'A') || (userDataCheck.at(r) == 'e') || (userDataCheck.at(r) == 'E') || (userDataCheck.at(r) == 'i') || (userDataCheck.at(r) == 'I') || (userDataCheck.at(r) == 'o') || (userDataCheck.at(r) == 'O') || (userDataCheck.at(r) == 'u') || (userDataCheck.at(r) == 'U')){
allVows.push_back(userData.at(r));
}
else if ((userDataCheck.at(r) >= 'A' && userDataCheck.at(r) <= 'Z') || (userDataCheck.at(r) >= 'a' && userDataCheck.at(r) <= 'z')){
allCons.push_back(userData.at(r));
}
else {
continue;;
}
}
}
}
The error here is in these lines:
allVows.push_back(userData.at(r));
allCons.push_back(userData.at(r));
the r variable is your index into the current string, but here you're using it to index into the vector, which looks like a typo to me. You can make this less error prone using range-for loops:
for (const std::string& str : userData) {
for (char c : str) {
if (c == 'a' || c == 'A' || ...) {
allVows.push_back(c);
}
else if (...) {
....
}
}
}
which I hope you'll agree also has the benefit of being more readable due to less noise. You can further simplify your checks with a few standard library functions:
for (const std::string& str : userData) {
for (char c : str) {
if (!std::isalpha(c)) continue; // skip non-alphabetical
char cap = std::toupper(c); // capitalise the char
if (cap == 'A' || cap == 'E' || cap == 'I' || cap == 'O' || cap == 'U') {
allVows.push_back(c);
}
else {
allCons.push_back(c);
}
}
}
Since this question is about debugging actually, I think it is a nice illustration of how the usage of std::algorithms of C++ can decrease the effort needed to see what is wrong with a non working code.
Here is how it can be restructured:
bool isVowel(char letter)
{
return letter == 'A' || letter == 'a' ||
letter == 'E' || letter == 'e'||
letter == 'O' || letter == 'o'||
letter == 'Y' || letter == 'y'||
letter == 'U' || letter == 'u';
}
bool isConsonant(char letter)
{
return std::isalpha(letter) && !isVowel(letter);
}
void categorizeLetters(const std::vector<std::string> &words, std::vector<char> &vowels, std::vector<char> &consonants)
{
for( const std::string &word : words){
std::copy_if(word.begin(), word.end(), std::back_inserter(vowels), isVowel);
std::copy_if(word.begin(), word.end(), std::back_inserter(consonants), isConsonant);
}
}
With a solution like this, you avoid the error-prone access-with-index that lead to your problem. Also, code is readable and comprehensive

while loop runs even if condition isnt true

i am trying to make a calculator using c++, im trying to implement error handling, so if the user enters a non arithmetic operator, it will tell the user to please enter an operator, using a while loop. the problem is, even when the user enters an operator on the first run through, the while loop still executes.
I have tried not putting a space between while, and the perinthesis, also, i tried not using a variable, and just putting all the conditionals to trigger the loop.
string getop()
{
string op;
int check = 1;
cout << "Enter an operator (+ - / *): ";
cin >> op;
if ((op != "+") || (op != "-") || (op != "/") || (op != "*"))
{
check = 0;
}
while (check == 0) // while the input is not a valid operator
{
cout << "Invalid operator, please enter a valid operator: ";
cin >> op;
if ((op == "+") || (op == "-") || (op == "/") || (op == "*"))
check = 1;
}
return op;
}
the problem is, even when the user enters an operator on the first run through, the while loop still executes.
Try:
(op != "+") && (op != "-") && (op != "/") && (op != "*")
Operator || is or operator (alternative, one or another is enough). You want operator &&, which forces all conditions to be true together.
You have a logic error:
if ((op != "+") || (op != "-") || (op != "/") || (op != "*"))
this will always yield true no matter what op is.
You want:
if ((op != "+") && (op != "-") && (op != "/") && (op != "*"))
A very good practise is to name your logical events. Also, AND chaining negations is rather unintuitive (and also unreadable). So an even better alternative would be:
bool is_valid = (op == "+") || (op == "-") || (op == "/") || (op == "*");
if (!is_valid)
check = 0;
You also shouldn't use namespace std; - you can read here why.
You want to use AND (&&), not OR (||):
if ((op != "+") && (op != "-") && (op != "/") && (op != "*"))
{
check = 0;
}
Your problem is right here:
if ((op != "+") || (op != "-") || (op != "/") || (op != "*"))
{
check = 0;
}
Suppose op is assigned a value of "+", that would mean that these conditions all evaluate to true: op != "-", op != "/", op != "*".
Since you are using the OR (||) operator, check will be assigned a value of 0 if any of those conditions are true. In fact, one of those four conditions will always be true no matter what value op has.
You should use AND (&&) instead so that check is assigned 0 when all of the conditions are true:
if ((op != "+") && (op != "-") && (op != "/") && (op != "*"))
{
check = 0;
}
when you have a chain of assertions joined by &&, normally the negation consists in negate all the assertions and change all the && operators by || or viceversa.
You changed all the asserrtions, negating them, but you forgot to change the || by &&.
Look for Demorgan's theorem in Google.

How to write the compare line with better syntax

This is my line of code.
Can I replace this with much more graceful syntax?
if ( colDiffuseCompare == colDiffuseReplace && colAmbientCompare == colAmbientReplace && colEmissionCompare == colEmissionReplace && colSpecularCompare == colSpecularReplace)
{
return true;
}
else
{
return false;
}
You don't need the if() for such case:
return colDiffuseCompare == colDiffuseReplace &&
colAmbientCompare == colAmbientReplace &&
colEmissionCompare == colEmissionReplace &&
colSpecularCompare == colSpecularReplace;
There's no way to avoid combining the single conditions though.

warning: expression results unused

Why does the compiler issue the warning: Expression results unused in the last else statement of this code?
PowerballLottery::WinningPossibility PowerballLottery::checkTicket(PowerballTicket ticket)
{
int count = 0;
if (ticket.getBall1() == getball1() || ticket.getBall1() == getball2() || ticket.getBall1() == getball3() || ticket.getBall1() == getball4() || ticket.getBall1() == getball5())
count++;
if (ticket.getBall2() == getball1() || ticket.getBall2() == getball2() || ticket.getBall2() == getball3() || ticket.getBall2() == getball4() || ticket.getBall2() == getball5())
count++;
if (ticket.getBall3() == getball1() || ticket.getBall3() == getball2() || ticket.getBall3() == getball3() || ticket.getBall3() == getball4() || ticket.getBall3() == getball5())
count++;
if (ticket.getBall4() == getball1() || ticket.getBall4() == getball2() || ticket.getBall4() == getball3() || ticket.getBall4() == getball4() || ticket.getBall4() == getball5())
count++;
if (ticket.getBall5() == getball1() || ticket.getBall5() == getball2() || ticket.getBall5() == getball3() || ticket.getBall5() == getball4() || ticket.getBall5() == getball5())
count++;
bool match = false;
if (ticket.getPowerball() == getpowerball())
match = true;
if ((count == 0) && (match == false))
return PowerballLottery::WinningPossibility::NOTWINNING;
else if ((count == 0) && (match == true))
return PowerballLottery::WinningPossibility::POWERBALL;
else if ((count == 1) && (match == true))
return PowerballLottery::WinningPossibility::ONEPLUSPOWERBALL;
else if ((count == 2) && (match == true))
return PowerballLottery::WinningPossibility::TWOPLUSPOWERBALL;
else if ((count == 3) && (match == false))
return PowerballLottery::WinningPossibility::THREE;
else if ((count == 3) && (match == true))
return PowerballLottery::WinningPossibility::THREEPLUSPOWERBALL;
else if ((count == 4) && (match == false))
return PowerballLottery::WinningPossibility::FOUR;
else if ((count == 4) && (match == true))
return PowerballLottery::WinningPossibility::FOURPLUSPOWERBALL;
else if ((count == 5) && (match == false))
return PowerballLottery::WinningPossibility::FIVE;
else ((count == 5) && (match == true));
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
}
Effectively, the code is
if ((count == 0) && (match == false))
....
else if ((count == 5) && (match == false))
return PowerballLottery::WinningPossibility::FIVE;
else
((count == 5) && (match == true)); //<- Expression results unused
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
As said from #AlexD's answer this is primarily a problem with how you had formatted the code, and that warning appears because
else ((count == 5) && (match == true));
that statement actually isn't used to do any computation stored in a result, or making a branch decision based on it.
The
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
statement is executed regardless anyways.
Reminds a bit about the famous apple OpenSSL goto fail; bug:
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail; /* MISTAKE! THIS LINE SHOULD NOT BE HERE */
Others have already pointed out the problem the compiler was warning you about.
Now let's consider the problem it didn't warn you about: your code is much more complex than there's any good reason for it to be.
In essence, the users picks and the balls chosen in the lottery (other than the power-ball) form sets. What we care about is the size of the intersection of those two sets. The C++ standard library gives us tools to make that task a lot simpler (and it looks to me like the way you've designed your PowerBallTicket class is doing more to hinder than help too):
std::set<int> lottery {
getball1(),
getball2(),
getball3(),
getball4(),
getball5()
};
std::set<int> tick {
ticket.getball1(),
ticket.getball2(),
ticket.getball3(),
ticket.getball4(),
ticket.getball5()
};
std::vector<int> matches;
std::set_intersection(lottery.begin(), lottery.end(),
tick.begin(), tick.end(),
std::back_inserter(matches));
That gives us the matches between the two. From there, we have the problem of converting the number of matches (plus whether the Powerball matched) to choose which enumeration value to return. One easy way to do that is to is an array:
WinningPossibility rets[][6] = {
{ NOTWINNING, ONE, TWO, THREE, FOUR, FIVE},
{ POWERBALL, ONEPLUS, TWOPLUS, THREEPLUS, FOURPLUS, FIVEPLUS }
};
With those in place, our return looks something like this:
return rets[ticket.getpowerball() == getpowerball()][matches.size()];
The code above points toward an improvement: instead of all those getballX() member functions, you should just store the data in a set to start with, and operate directly on those sets. In this case, it looks like you have quasi-classes, with "encapsulation" that's losing a great deal, and gaining little (probably nothing).
You can say else <statement> or else if (<expression>) <statement>; you have the expression without the if, which the compiler is doing its best with.

Evaluating a single char in an if statement: C++

I am having some troubles with my if loop.
First off I have I assigned char sign.
void evaluate_ps(istream& input)
{
char sign;
input >> sign;
cout << sign << endl;
check(sign);
}
That prints / so my sign has the value '/'
Then I go to my void check(char operation) function
void check(char operation)
{
if(operation != '-' || operation != '+' ||
operation != '*' || operation != '/')
{
return false;
}
else return true;
}
and it's returning false... WHY!!!! I can't seem to figure this out.
Thanks everyone.
This happens because you are using the || (OR) operator. When operation is / the check operation != '-' returns true. Since || is short circuited, the entire expression returns true.
Change it to && (AND):
if (operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Another way to write this is:
if (!(operation == '-' || operation == '+' ||
operation == '*' || operation == '/'))
You probably meant all your || to be &&:
if(operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Otherwise, it will always enter the if-statement since a character will always not equal one of 4 different things.
The if statement is responding to the / not equaling one of the other values
Think about "or" even in a general sense
if blue is not green or is not red or is not blue say nope
you would need to do something like the following:
if (operation != '+' && operation != '-' && operation != '/' && operation != '*') {
return false;
}
return true;
this way its like this
if blue is not green and is not red and is not blue say nope