While loop going past limit - c++

while (('\0' != *str1) && ('\0' != *str2) &&
(false == sensi) ? (std::toupper(*str1) == std::toupper(*str2)) : (*str1 == *str2)) {
++str1;
++str2;
}
This code keeps looping even past the NULL terminator.
There must be something incredibly obvious I am missing here, but I simply cannot see it.
If either one of those chunks of code between the && gets evaluated as false, it should break, but it does not do so and keeps parsing the string even past the NULL terminator into gibberish.

while (('\0' != *str1) && ('\0' != *str2) &&
(false == sensi) ? (std::toupper(*str1) == std::toupper(*str2)) : (*str1 == *str2))
The ternary operator ?: has lower precedence than nearly all other operators, including the logical AND &&. So, the &&s get applied first, and thus what you are saying here is:
if str1 is not at its NUL terminator, && str2 is not at its own, && we are not comparing case-sensitively,
then ? loop while the strings' current characters are equal case-insensitively,
else : loop while the strings' current characters are equal exactly.
Therefore, you will loop forever if the strings are equal, or at least past their NUL terminators and into Undefined Behaviour Land.
What you instead mean is this, where we wrap the entire ternary expression in parentheses, to override its default precedence and thus make the language evaluate it as the 3rd condition of the &&:
while ( *str1 != '\0' && *str2 != '\0' &&
(!sensi ? std::toupper(*str1) == std::toupper(*str2) : *str1 == *str2) )
i.e. to loop while:
str1 is not at its NUL terminator, &&
str2 is not at its own, &&
( the strings' current characters are equal in ?: the way specified by sensi ).
I would suggest to review operator precedence here, not overuse parentheses where redundant, and not use Yoda conditionals. Also, this large compound condition could perhaps best be expressed as a separate function taking the 2 strs as input and checking each condition separately, to avoid confusing long logical tests.

Related

Why does (0 && 1 == 0) not evaluate to true?

In my if statement, the first condition for && is 0 (false), so the expression 0 && (a++) is equal to 0, right? Then 0==0 it should be true. Why am I getting else here? Please explain!
int a=0;
if(0 && (a++)==0)
{
printf("Inside if");
}
else
{
printf("Else");
}
printf("%i",a);
The == operator has a higher priority than the && operator, so this line:
if(0 && (a++)==0)
is treated like this:
if( 0 && ((a++)==0) )
So the whole expression under the if is false, and a++ is not even evaluated due to short circuitry of the && operator.
You can read about Operator Precedence and Associativity on cppreference.com.
When in doubt, you should use parenthesis to express your intention clearly. In this case, it should be:
if( (0 && (a++)) == 0 )
Though, it does not make any sense, as it always evaluates to true and a++ is not incremented here, either.
As already mentioned, the precedence of == is higher than precedence of &&, so the statement is resolved into
if( 0 && ((a++)==0))
However, still even if you add the correct order of brackets, a++ returns the original value of a, which is 0, but the a is incremented. If you want to return the updated value of a, you should write ++a
if( ((++a) && 0) == 0 )
Although the question seems easy it's very error-prone.
We need to know the precedence of various operators involved in this.
1. postfix (++)
2. ==
3. Logical AND (&&)
the final expression can be seen as: if ( (0 && (a++)) == 0 )
which is true. Hence statement under if is evaluated to be true.

Comparison between pointer and integer in string class - C++

I'm new to C++.
string str = "WWWHBBB";
if(str[mid] == "H" && str[0] != "W") return; // corrected after comments for second operand
The above line with if condition gives me an error.
Comparison between pointer and integer ('std::__1::basic_string, std::__1::allocator >::value_type' (aka 'char') and 'const char *')
I have searched the internet enough to know that array style access is fine in strings. Error basically is pointing out comparison about pointer and integer. Really? I thought I was comparing character H to another character in string str.
I tried if str[mid] really returns an iterator I should do *str[mid]. Nah! Didn't work either.
In the expression of the if statement
if(str[mid] == "H" && str[mid] != "W") return;
the string literals "H" and "W" that have the type const char[2] are implicitly converted to pointers to their first characters of the type const char *.
So you are trying to compare a character returned by the expression str[mid] with a pointer.
Instead of the string literals you need to use character literals like to compare characters
if(str[mid] == 'H' && str[mid] != 'W') return;
You could also write like
if(str[mid] == *"H" && str[mid] != *"W") return;
or
if(str[mid] == "H"[0] && str[mid] != "W"[0]) return;
dereferencing the pointers but this will be confusing
Pay attention to that if str[mid] == 'H' then the second operand will always yield true. So it is enough to write
if( str[mid] == 'H' ) return;
You'd want to compare with a single char
if (str[mid] == 'H' && str[mid] != 'W') return;
Note that double-quotes in this case refer to a const char[] whereas single-quotes refer to a single char.
The warning is telling you that the only way to make those comparisons in your case would be to compare the lhs char (result of str[mid]) to the rhs would be to let the array decay to const char* and compare the pointer address to the char.

Incorrect string comparison

I have a problem i cannot figure out at all!
in my program the user enters numbers to be sorted. i had to be able to sort infinity, negative infinity and the so called "Nullity" (these i defined early in the program)
if the user wants to enter infinity for example they have to enter "Pinf" into the string.
my issue is i store the users input in a std::string and then check if the string is "pinf" or "Pinf" even tho i have entered the number 3 so the string is "3", it still goes into the if statement, what have i done wrong?!
My code is below;
string Temp;
cin>> Temp;
if (Temp.find("Pinf")||Temp.find("pinf")) {
Num = Pinfinity;
}
It thinks the if statement is true everytime.
1.Error - you are using | instead of ||.
2.Error - findreturns
The position of the first character of the first match. If no matches
were found, the function returns string::npos.
You should change
if (Temp.find("Pinf")|Temp.find("pinf")) {
to
if ((Temp.find("Pinf") != string::npos) || (Temp.find("pinf") != string::npos)) {
If you are just searching for Pinf or pinf then you can use this. Note the logical or operator is ||.
if (Temp == "Pinf" || Temp == "pinf") {
| is a bitwise or operator. Use || in place of |
if ( Temp.find("Pinf") != npos || Temp.find("pinf") != npos )

If statement with negative values

In an if statement like this:
if(strcmp(str1,str2))
strcmp() can return a negative value, and if it does, does the if statement consider it to be TRUE or FALSE.
In C++, the if statement treats any nonzero value as true. A negative value is not zero, so it will be considered true. The following two statements are equivalent:
if (strcmp(str1, str2))
if (strcmp(str1, str2) != 0)
The strcmp function when used with an if statement can lead to some very unreadable code. The following statement says to call foo if and only if str1 is different than str2.
if (strcmp(str1, str2)) foo();
Some would argue this is somewhat unexpected and unreadable, but it's due to the fact that strcmp is not really meant to be used this way as it does not return a bool. If you check out this great reference you'll see that it returns an integral value which is meant to indicate the relationship between the strings. strcmp can tell you much more than simply whether or not two strings are the same. According to the reference strcmp returns:
0 if both strings are equal
A positive value if the first character that does not match has a greater value in str1 than in str2
A negative value if the first character that does not match has a greater value in str2 than in str1
Because an if statement will coerce any non-zero integer value into a boolean value of true the if statement if (strcmp(str1, str2)) foo() will always interpret true and execute foo, except when str1 and str2 are equal (in which case the if statement will interpret false and foo will not be executed).
The more common way to use strcmp with an if statement is to combine your call to strcmp with a binary comparison within the if statement, testing against an integral value:
if (strcmp(str1, str2) == 0) foo(); // foo executed iff str1 and str2 are equal
if (strcmp(str1, str2) != 0) foo(); // foo executed iff str1 and str2 are not equal
You might also use strcmp with an if statement to sort strings, strcmp is ideal for this because it returns based on the first unmatching character of the string. You could use it with something like the following (untested code):
bool swapped = false;
do {
for (i = 1; i < numStrings; i++) {
if (strcmp(str[i-1], str[i]) > 0) {
swap(i-1, i);
swapped = true;
}
}
} while (swapped);
When an integer value is converted to a Boolean value, 0 is false and any other value is true.
C converts any non-zero value to true and only zero is false.
Note that if(strcmp(str1, str2)) is NEARLY always "wrong". You either want one of:
if (strcmp(str1, str2) == 0) to detect that two strings are equal
if (strcmp(str1, str2) > 0) to detect that str1 > str2
if (strcmp(str1, str2) < 0) to detect that str1 < str2
The only reason for if(strcmp(str1, str2)) is for detecting that str1 is different from str2 - which is nearly always not what you want.
And of coruse, in C++, you probably shouldn't be using strcmp at all - since you have std::string that you can just write what you want as a comparison, e.g. if (str1 > str2) or if (str1 != str2), and it's immediately obvious to most people what it means without further questions.

C++: Pointer assignment warning on strchr()

I get the error assignment makes pointer from integer without a cast on the following code, what does it mean?
char * splitter;
if(splitter = strchr(key, ':') != NULL && *(splitter + 1) == ' ')
It is because of the priority of operations. You need to put an extra set of parens to make sure it happens in the right order:
char * splitter;
if((splitter = strchr(key, ':')) != NULL && *(splitter + 1) == ' ')
otherwise the it will evaluate as this:
splitter = (strchr(key, ':') != NULL)
Since strchr(key, ':') != NULL will evaluate to either a 1 or a 0, in your example, you are assigning an integer to a pointer type, hence the warning.
however, i would just write it as in your second example, since it is simpler and less error prone. Making it one line shorter doesn't add anything except complexity.
The not-equal operator != has higher precedence than the assignment operator =, so your original line reads like splitter = (strchr(key, ':') != NULL) rather than your intended (splitter = strchr(key, ':)) != NULL, so the compiler tries to assign to splitter the result of the comparison between strchr() and NULL.
The != operator has a higher precedence than the = operator. That means your expression splitter = strchr(key, ':') != NULL is actually interpreted as splitter = (strchr(key, ':') != NULL).
Put the assignment into parentheses to increase the precedence of that part:
(splitter = strchr(key, ':')) != NULL
The != has higher precendence than the =. You should fully parenthesize:
if (((splitter = strchr(key, ':')) != NULL) && (*(splitter + 1) == ' '))