Because both strings are empty. In fact, calling the method c_str() will give a an array, which has at its first position ([0]) the null terminator (0x00 or '\0'). What follows the 0x00, is just rubbish.
In fact, check the card length, it will be 0.
(btw, there are some bugs in the code too. It always return false if the string have the same length, and it will always return true otherwise. EDIT: following the Nick Gammon's answer I also noticed that you get the pointer of the same string :). I corrected also this).
I think the code should be rewritten to:
if (str.length() == card.length())
{
uchar *p1 = (uchar*)str.c_str(), *p2 = (uchar*)card.c_str();
for (int i = 0; i < card.length(); i++)
if (p1[i] != p2[i])
return false;
}
else
return false;
return true;
EDIT:
I add there what I wrote in the comments, for future reference, and explained in details.
The problem lies on the String class, which on one hand, it allows adding '\0' characters, through the method concat(char*), but on the other, it uses the strcmp (and other C standard functions) to perform compare between strings. This leads to unpredictable results. Maybe this is a bug in the String class.
In particular, SoftwareSerial extends Stream. Stream::readString() (which is used in the program to get str), is implemented as follows:
String Stream::readString()
{
String ret;
int c = timedRead();
while (c >= 0)
{
ret += (char)c;
c = timedRead();
}
return ret;
}
The line ret += (char)c;
uses operator +=, which is implemented in WString.h as:
String & operator += (char c) {concat(c); return (*this);}
Note that readString() also allows adding any non negative value of c, including 0, i.e. '\0' - see while (c >= 0) in its code above
In turn, concat(char c) is implemented in WString.cpp as:
unsigned char String::concat(char c)
{
char buf[2];
buf[0] = c;
buf[1] = 0;
return concat(buf, 1);
}
And concat(const char *cstr, unsigned int length) is implemented as:
unsigned char String::concat(const char *cstr, unsigned int length)
{
unsigned int newlen = len + length;
if (!cstr) return 0;
if (length == 0) return 1;
if (!reserve(newlen)) return 0;
strcpy(buffer + len, cstr);
len = newlen;
return 1;
}
In the above method, length (instead of strlen) is used to determine the length of the string to add, and the new length is calculated using it:
newlen = len + length;
That's the bug: you can add a '\0' char to the string, and this will also result in an increased length of the string. They should have checked if length <= strlen(cstr), before performing this concat operation.
Now, if you call the method String::equals or use the operator == (it is the same, as it is defined in WString.h as unsigned char operator == (const String &rhs) const {return equals(rhs);}
), you call this code:
unsigned char String::equals(const String &s2) const
{
return (len == s2.len && compareTo(s2) == 0);
}
Which, in turn, calls:
int String::compareTo(const String &s) const
{
if (!buffer || !s.buffer) {
if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
if (buffer && len > 0) return *(unsigned char *)buffer;
return 0;
}
return strcmp(buffer, s.buffer);
}
And strcmp ends its compare operation if it first encounters a null operator (or when a compare mismatch occurs).
Therefore in your case, readString() added a null character to the "ret" String at first, and then some other characters. This created a String which begins with '\0'. Such string is equal to any other string beginning with a '\0', regardless what follows '\0'. But if you call length(), you'll get "len" (which String::concat() does not correctly calculate, and it will be non 0), as you can find in WString.h:
inline unsigned int length(void) const {return len;}
Disclaimer: future versions of WString.h and WString.cpp could have fixed this bug.