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.
Related
I am new to programming and I need to search any string to see if it includes only the letters a,b,c,d,e or f. The minute the program finds a letter that is not one of those the program should return false. Here is my function
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true;
}
else {
return false;
}
index++;
}
}
Thank you very much for nay help! :)
The moment the return statement is encountered, the function is exited. This means that the moment any of the characters 'a', 'b', 'c', 'd', 'e', 'f' is encountered while iterating, due to the return statement the function will be exited immediately.
You can use std::string::find_first_not_of as shown below:
std::string input = "somearbitrarystring";
std::string validChars = "abcdef";
std::size_t found = input.find_first_not_of(validChars);
if(found != std::string::npos)
std::cout << "Found nonfavorite character " <<input[found]<<" at position "<<found<< std::endl;
else
{
std::cout<<"Only favorite characters found"<<std::endl;
}
If you unroll the loop by hand, you will spot the problem immediately:
if ((word[0] == 'a') || (word[0] == 'b') || (word[0] == 'c')||
(word[0] == 'd')|| (word[0] == 'e')|| (word[0] == 'f')) {
return true;
}
else {
return false;
}
if ((word[1] == 'a') || (word[1] == 'b') || (word[1] == 'c')||
(word[1] == 'd')|| (word[1] == 'e')|| (word[1] == 'f')) {
return true;
}
else {
return false;
}
//...
That is, the return value depends only on the first element.
"The minute the program finds a letter that is not one of those the program should return false" means
if ((word[0] != 'a') || (word[0] != 'b') || (word[0] != 'c')||
(word[0] != 'd')|| (word[0] != 'e')|| (word[0] != 'f')) {
return false;
}
if ((word[1] != 'a') || (word[1] != 'b') || (word[1] != 'c')||
(word[1] != 'd')|| (word[1] != 'e')|| (word[1] != 'f')) {
return false;
}
// ...
// After checking all the characters, you know what all them were in
// your desired set, so you can return unconditionally.
return true;
or, with a loop:
while (index < length) {
if ((word[index] != 'a') || (word[index] != 'b') || (word[index] != 'c')||
(word[index] != 'd')|| (word[index] != 'e')|| (word[index] != 'f')) {
return false;
}
index++;
}
return true;
bool is_favorite(string word){
return ( word.find_first_not_of( "abcdef" ) == std::string::npos );
}
It returns true if, and only if, there are only the characters 'a' through 'f' in the string. Any other character ends the search immediately.
And if you exchange string word with const string & word, your function will not have to create a copy of each word you pass to it, but work on a read-only reference to it, improving efficiency.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (word[index] > 'f' || word[index] < 'a')
return false;
index++;
}
return true;
}
The return true is logically in the wrong place in your code.
Your version returns true as soon as it finds one letter that is a through f. It's premature to conclude that the whole string is valid at that point, because there may yet be an invalid character later in the string.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true; // This is premature.
}
else {
return false;
}
index++;
}
}
Minimal change that illustrates where the return true should be: after the loop. The return true is reached only if and only if we did not detect any invalid characters in the loop.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
// Do nothing here
}
else {
return false;
}
index++;
}
return true;
}
Obviously now that the affirmative block of the if is empty, you could refactor a little and only check for the negative condition. The logic of it should read closely to the way you described the problem in words:
"The minute the program finds a letter that is not one of those the program should return false."
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (!is_letter_a_through_f((word[index])
return false;
index++;
}
return true;
}
I replaced your large logical check against many characters with a function in the above code to make it more readable. I trust you do that without difficulty. My own preference is to keep statements short so that they are readable, and so that when you read the code, you can hold in your short-term memory the logic of what you are saying about control flow without being overloaded by the mechanics of your letter comparison.
I'm writing an NMEAParser library. As its name suggests, it parses NMEA sentences. Nothing crazy.
Its entry point is a function that accepts an NMEA string as its only parameter and looks at its beginning to pass it to the right decoder. Here is the function:
bool NMEAParser::dispatch(const char *str) {
if (!str[0]) {
return false;
}
//check NMEA string type
if (str[0] == '$') {
//PLSR245X
if (str[1] == 'P' && str[2] == 'L' && str[3] == 'S' && str[4] == 'R' && str[5] == ',' && str[6] == '2' && str[7] == '4' && str[8] == '5' && str[9] == ',') {
if (str[10] == '1')
return parsePLSR2451(str);
if (str[10] == '2')
return parsePLSR2452(str);
if (str[10] == '7')
return parsePLSR2457(str);
} else if (str[1] == 'G' && str[2] == 'P') {
//GPGGA
if (str[3] == 'G' && str[4] == 'G' && str[5] == 'A')
return parseGPGGA(str);
//GPGSA
else if (str[3] == 'G' && str[4] == 'S' && str[5] == 'A')
return parseGPGSA(str);
//GPGSV
else if (str[3] == 'G' && str[4] == 'S' && str[5] == 'V')
return parseGPGSV(str);
//GPRMC
else if (str[3] == 'R' && str[4] == 'M' && str[5] == 'C')
return parseGPRMC(str);
//GPVTG
else if (str[3] == 'V' && str[4] == 'T' && str[5] == 'G')
return parseGPVTG(str);
//GPTXT
else if (str[3] == 'T' && str[4] == 'X' && str[5] == 'T')
return parseGPTXT(str);
//GPGLL
else if (str[3] == 'G' && str[4] == 'L' && str[5] == 'L')
return parseGPGLL(str);
}
//HCHDG
else if (str[1] == 'H' && str[2] == 'C' && str[3] == 'H' && str[4] == 'D' && str[5] == 'G')
return parseHCHDG(str);
}
return false;
}
The problem I have is that this function's cyclomatic complexity is quite high, and my SonarQube complains about it:
It's not really a problem as the code is quite easy to read. But I was wondering how I could reduce its complexity while still keeping it simple to read and efficient.
You can simplify this quite a lot:
if (std::string_view{str, 10} == "$PLSR,245,")
{
switch (str[10])
{
case '1' : return parsePLSR2451(str);
case '2' : return parsePLSR2452(str);
case '7' : return parsePLSR2457(str);
}
}
else if (std::string_view{str + 1, 2} == "GP")
{
auto s = std::string_view{str + 3, 3};
if (s == "GGA")
return parseGPGGA(str);
if (s == "GSA")
return parseGPGSA(str);
// ... etc
}
else if (std::string_view{str + 1, 5} == "HCHDG")
{
return parseHCHDG(str);
}
return false;
There's no extra strings being constructed either, so it should be at least as efficient.
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.
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.
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;
}