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.
Related
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.
motion->bone_frames[0].name == model->bones[0].bone_name//it return 0 . it should be 1
motion->bone_frames[0].name.Compare(model->bones[0].bone_name)//it return 1 . it should be 0
wcscmp(motion->bone_frames[0].name.c_str(), model->bones[0].bone_name.c_str()) //it return 0 it should be 0 correct
I cant understand std::string compare functions why have different result to wcscmp.
Can i know why these results are different?
Is it cause of different is length?
Because they are not equal. Check the size of your strings in the image that you've attached. In the first there are '\0' at the end of the string, that are characters as well.
wcscmp stops comparing when it hits L'\0'. A std::wstring will consider the size() of the strings.
The string == and compare will return "different" results as the first returns true and the second returns 0 for equal strings. See Differences between C++ string == and compare()?
The standard operator== returns lhs.compare(rhs) == 0.
Why is the if statment always true?
char dot[] = ".";
char twoDots[] = "..";
cout << "d_name is " << ent->d_name << endl;
if(strcmp(ent->d_name, dot) || strcmp(ent->d_name, twoDots))
Am I using strcmp wrong?
strcmp() returns 0 when strings equal and a string cannot be both "." and "..". meaning one side of the || will always be non-zero and therefore the condition is always true.
To correct:
if(0 == strcmp(ent->d_name, dot) || 0 == strcmp(ent->d_name, twoDots))
An alternative would be to use std::string to store the dot variables and use ==:
#include <string>
const std::string dot(".");
const std::string twoDots("..");
if (ent->d_name == dot || ent->d_name == twoDots)
strcmp() returns nonzero in case of a difference (and thus evaluates to true).
Also have a look at the docs (links below). Also have a look on std::string which provides an operator==() for tasks like this. See this answer for the how.
Returns an integral value indicating the relationship between the strings:
A zero value indicates that both strings are equal.
A value greater than zero indicates that the first character that does not match has a greater value in str1 than in str2; And a value less than zero indicates the opposite.
http://www.cplusplus.com/reference/clibrary/cstring/strcmp/
The return value for each of these functions indicates the lexicographic relation of string1 to string2.
Value Relationship of string1 to string2
< 0 string1 less than string2
0 string1 identical to string2
> 0 string1 greater than string2
http://msdn.microsoft.com/en-us/library/e0z9k731%28v=vs.80%29.aspx
strcmp returns -1, 0, or 1 if the strings are lexicographically prior, equal, or later respectively.
To check whether strings are equal, use strcmp(s1, s2) == 0.
Because strcmp returns 0 when equal and 1 or -1 when different, at least one of the two strcmp is returning 1 or -1, the || will return true when any condition is something different of 0, you should do this...
if(strcmp(ent->d_name, dot) == 0 || strcmp(ent->d_name, twoDots) == 0)
I added == 0 after every strcmp
strcmp by itself does not return a boolean. Instead, it returns an int. 0 if match, other if no match. So this should help:
if(0 == strcmp(d_name, dot) || 0 == strcmp(d_name, twoDots)) {
// Other code here
}
case 1:
std::string dd = "5A"
char checkSum[9]
checkSum[0] = '5';
checkSum[1] = 'A';
if(strcmp(dd.c_str(),checkSum) == 1){
return 1;
}
else {return 0;}
RESULT: returns 1 //Correct!
case 2:
std::string dd = "0A"
char checkSum[9];
checkSum[0] = '5';
checkSum[1] = 'A';
if(strcmp(dd.c_str(),checkSum) == 1){
return 1;
}
else {return 0;}
RESULT: returns 0 //Correct!
case 3:
std::string dd = "5A"
char checkSum[9]
checkSum[0] = '0';
checkSum[1] = 'A';
if(strcmp(dd.c_str(),checkSum) == 1){
return 1;
}
else {return 0;}
RESULT: returns 1 //Not Correct!
Anyone knows whats wrong? thx!
strcmp requires two null-terminated strings, but you are not adding a null-terminator to checkSum.
This is why case 1 returns 1 when in fact it should return 0. Note that your expected values are incorrect. In case 1, once you have added in the null-terminator, the two strings should compare as equal. And so strcmp will return 0 and your code should also return 0.
For case 2, strcmp("0A", "5A") returns a negative value since '0'<'5' and so your code should return 0.
For case 3, strcmp("5A", "0A") returns a positive value, and it just so happens that the positive value is 1 which you are mistakenly testing for by equality.
In all cases testing for a value of 1 is incorrect since strcmp never promises to return 1. It promises to return either:
a value of 0 to indicate that the two strings are equal, or,
a positive value to indicate that str1 compares greater than str2, or,
a negative value to indicate that str1 compares less than str2.
The only valid comparisons on the return value of strcmp are therefore ==0, >0 or <0.
You need to revisit the documentation for strcmp and correct your understanding of how to interpret the return value.
Your checksum contain undefined data you don't add a '\0' termination character in it. It is unexpected behavior if you call the strcmp. You could declare your checksum as:
char checkSum[9] = {0};
but better solution is to avoid unsafe character arrays, use std::string instead.
strcmp return value:
A zero value indicates that both strings are equal. A value greater
than zero indicates that the first character that does not match has a
greater value in str1 than in str2; And a value less than zero
indicates the opposite.
(Extract from http://www.cplusplus.com/reference/clibrary/cstring/strcmp/)
Also you should never compare the result of strcmp with anything else then zero as in
strcmp(s1, s2) == 0
strcmp(s1, s2) > 0
strcmp(s1, s2) < 0
strcmp(s1, s2) != 0
as the standard does not guerantee a 1 (or -1) in the case of difference.
string temp is equal to "ZERO:\t.WORD\t1" from my debugger. (the first line of my file)
string temp = RemoveWhiteSpace(data);
int i = 0;
if ( temp.length() > 0 && isalpha(temp[0]) )
cout << "without true worked" << endl;
if ( temp.length() > 0 && isalpha(temp[0]) == true )
cout << "with true worked" << endl;
This is my code to check if first character of temp is a a-z,A-Z. The first if statement will evaluate to true and the 2nd to false. WHY?!?!?! I have tried this even without the "temp.length() > 0 &&" and it still evaluates false. It just hates the "== true". The only thing I can think of is that isalpha() returns != 0 and true == 1. Then, you could get isalpha() == 2 != 1. But, I have no idea if C++ is that ... weird.
BTW, I dont need to know that the "== true" is logically pointless. I know.
output was
without true worked
Compiled with CodeBlock using GNU GCC on Ubuntu 9.10 (if this matters any)
The is* functions are only guaranteed to return a non-zero value if true, NOT necessarily a 1. A typical implementation is table based, with one entry in the table for each character value, and a set of bits defining which bit means what. The is* function will just AND the right bitmask with the table value, and return that, which will only be the value 1 for whichever type happens to have been given bit position 0.
E.g.:
#define __digit 1
#define __lower 2
#define __upper 4
extern int __type_table[];
int isdigit(int c) {
return __type_table[c+1] & __digit;
}
int isalpha(int c) {
return __type_table[c+1] & (__lower | __upper);
}
int islower(int c) {
return __type_table[c+1] & __lower;
}
int isupper(int c) {
return __type_table[c+1] & __upper;
}
Where __type_table is defined as something like int __type_table[UINT_MAX+1]; and would be initialized so (for example) __type_table['0'+1] == __digit and __type_table['A'+1] == __upper.
In case you care, the '+1' part is to leave a spot at the beginning of the table for EOF (which is typically defined as -1).
isalpha doesn't return true, it returns non-zero. This is quite common for API designed for C.
Note that in the expression isalpha(ch) == true, the subexpression true is promoted to type int with value 1.
Well, the documentation suggests that it returns either zero or non-zero, not necessarily just false or true. So you'd better check (isalpha(temp[0]) != 0).
Do not isalpha(ch) == true, but !!isalpha(ch) == true