How to compare const char* with a string in C++? - c++

I am working with C++ and I am trying to compare strings.
Below is my code which gives me back const char* -
const char* client_id() const {
return String(m_clientPos);
}
And now I am comparing the strings like this -
cout<<client_ptr->client_id()<< endl;
if (strcmp(client_ptr->client_id(), "Hello")) {
..
} else {
..
}
but it never goes into if statement. But my cout prints out Hello correctly. Is there anything wrong I am doing?

You need to do if (0 == strcmp(...
See http://www.cplusplus.com/reference/cstring/strcmp/
strcmp
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.

it never goes into if statement.
The strcmp function returns zero when the strings are the same, so you should see the code hit the else branch when the two strings are equal to each other.
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.
Since String does not look like a built-in class and assuming that you have access to its source, you may be better off making the comparison with const char* a member function of the String class.

Related

Is the comparison of strings or string views terminated at a null-character?

May a string or string_view include '\0' characters so that the following code prints 1 twice?
Or is this just implementation-defined?
#include <iostream>
#include <string_view>
#include <string>
using namespace std;
int main()
{
string_view sv( "\0hello world", 12 );
cout << (sv == sv) << endl;
string str( sv );
cout << (str == sv) << endl;
}
This isn't a duplicate to the question if strings can have embedded nulls since they obviously can. What I want to ask if the comparison of strings or string views is terminated at a 0-character.
Language lawyer answer since the standards documents are, by definition, the one true source of truth :-)
The standard is clear on this. In C++17 (since that's the tag you provided, but later iterations are similar), [string.operator==] states that, for using strings and/or string views, it:
Returns: lhs.compare(rhs) == 0.
The [string.compare] section further states that these all boil down to a comparison with a string view and explain that it:
Determines the effective length rlen of the strings to compare as the smaller of size() and sv.size(). The function then compares the two strings by calling traits::compare(data(), sv.data(), rlen).
These sizes are not restricted in any way by embedded nulls.
And, if you look at the traits information in table 54 of [char.traits.require], you'll see it's as clear as mud until you separate it out into sections:
X::compare(p,q,n) Returns int:
0 if for each i in [0,n), X::eq(p[i],q[i]) is true; else
a negative value if, for some j in [0,n), X::lt(p[j],q[j]) is true and for each i in [0,j) X::eq(p[i],q[i]) is true; else
a positive value.
The first bullet point is easy, it gives zero if every single character is equal.
The second is a little harder but it basically gives a negative value where the first difference between characters has the first string on the lower side (all previous characters are equal and the offending character is lower in the first string).
The third is just the default "if it's neither equal nor lesser, it must be greater".
nul-character is part of comparison, see https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp
Two strings are equal if both the size of lhs and rhs are equal and each character in lhs has equivalent character in rhs at the same position.

Subtracting two strings is giving wrong values in c++

#include<iostream>
#include<string>
using namespace std;
int main(){
string s1 = "abc";
string s2 = "xyz";
cout << s2.compare(s1) << endl;
return 0;
}
This is the Simple program in which I am just comparing two string and print the return value of the string::compare function.
Output:
1
The actual output for this program is 23.
This similar thing is happening with the ASCII characters.
#include<iostream>
#include<string>
using namespace std;
int main(){
cout << "a" - "A" << endl;
return 0;
}
The output I am getting after running the above code is:-
Output:
-2
But the output I was expecting is 32. I don't know what's the problem and why I am getting wrong output.
The output of std::string::compare() is according to the documentation:
Return value
negative value if *this appears before the character sequence specified by the arguments, in lexicographical order
zero if both character sequences compare equivalent
positive value if *this appears after the character sequence specified by the arguments, in lexicographical order
s2 is lexicographically later than s1, so compare returns a positive value, exactly as expected.
"a" - "A" is Undefined Behaviour. You are subtracting value of two pointers that do not point to the same array. Any output would be valid, as well as no output, crash, or demons flying out of your nose.
I suppose you wanted to subtract numeric values of characters, which would in fact give 32 (provided that your compiler is using an ASCII-compliant enconding):
'a' - 'A'
The return value of std::string::compare is:
negative value if *this appears before the character sequence specified by the arguments, in lexicographical order
zero if both character sequences compare equivalent
positive value if *this appears after the character sequence specified by the arguments, in lexicographical order
As you see, it is only defined as "negative / zero / positive" and the "negative" and "positive" values need not be -1 and 1.
"a" and "A" are string literals, which represents arrays. Arrays in expressions are automatically converted to pointers pointing at the first elements of them (some exception exists) and substraction of pointers will result in an integer representing the first pointer is how many elements from the second one.
What you wanted to use should be character constants, which are surrounded by ' instead of ".
cout << 'a' - 'A' << endl;
Alternatively, you can get the first elements of the arrays using subscripting operators.
cout << "a"[0] - "A"[0] << endl;
std::string::compare returns a positive or negative number or 0, it may return 1, -1 and 0 but doesn't have to.
"a" - "A" is performing pointer arithmetic on two unrelated pointers so has undefined behaviour. The behaviour you are seeing is probably that the compiler has laid out your constants in memory as "a\0A\0" so your constants are 2 bytes apart giving a result of -2.

std::string resize is ruining compare operator (==)

std::string resize causes strings that appear to be equal to no longer be equal. It can appear to be misleading when I hover over the variable in my debugger and they appear to hold the same value.
I think it comes down to the fact that I expected the == operator to stop at the first null character but it keeps going till the end of the size. I'm sure this is working as intended but I was stuck on an issue caused by this for a while so I wanted to see why you would keep comparing characters even after the first null character. thanks!
int main(void)
{
std::string test1;
test1.resize(10);
test1[0] = 'a';
std::string test2 = "a";
//they are not equal
bool same = (test1 == test2);
return 0;
}
test1 is the string "a\0\0\0\0\0\0\0\0\0". test2 is the string "a". They are not equal.
std::string can contain null characters. Its length is not the distance to the first null character. It does also guarantee that the memory buffer containing the characters of the string ends with an additional null character 1 beyond its length.
If you don't intend for the string to be longer but just want the memory, use std::string::reserve. Note that you cannot access elements beyond the end with [] legally, but pushing back or whatever won't cause any new memory allocations until you pass the reserve limit.
This is the intended behavior of std::string. Unlike a c-string a std::string can have as many null characters as you want. For instance "this\0 is\0 a\0 legal\0 std::string\0" would be legal to have as the contents for a std::string. You have to build it like
std::string nulls_inside("this\0 is\0 a\0 legal\0 std::string\0", sizeof("this\0 is\0 a\0 legal\0 std::string\0");
but you can also insert null characters into an existing std::string. In your case you're comparing
"a\0\0\0\0\0\0\0\0\0\0"
against
"a\0"
so it fails.

String comparison of char* to uint8_t [duplicate]

This question already has an answer here:
Comparing uint8_t data with string
(1 answer)
Closed 4 years ago.
I'm new to C and C++, and can't seem to work out how I need to compare these values:
Variable I'm being passed:
typedef struct {
uint8_t ssid[33];
String I want to match. I've tried both of these:
uint8_t AP_Match = "MatchString";
unsigned char* AP_Match = "MatchString";
How I've attempted to match:
if (strncmp(list[i].ssid, "MatchString")) {
if (list[i].ssid == AP_Match) {
if (list[i].ssid == "MatchString") {
// This one fails because String is undeclared, despite having
// an include line for string.h
if (String(reinterpret_cast<const char*>(conf.sta.ssid)) == 'MatchString') {
I've noodled around with this a few different ways, and done some searching. I know one or both of these may be the wrong type, but I'm not sure to get from where I am to working.
There is no such type as "String" defined by any C standard. A string is just an array of characters that are stored as unsigned values based on the chosen encoding. 'string.h' provides various functions for comparison, concatenation, etc. but it can only work if the values you are passing to it are coherent.
The operator "==" is also undefined for string comparisons, because it would require comparing each character at each index, for two arrays that may not be the same size and ultimately may use different encodings, despite the same underlying unsigned integer representation (raising the prospect of false positive comparisons). You can possibly define your own function to do it (note C doesn't allow overloading operators), but otherwise you're stuck with what the standard libraries provide.
Note that strncmp() takes a size parameter for the number of characters to compare (your code is missing this). https://www.tutorialspoint.com/c_standard_library/c_function_strncmp.htm
Otherwise you would be looking at the function strcmp(), which requires the input strings to be null-terminated (last character equal to '\0'). Ultimately it's up to you to consider what the possible combinations of inputs could be and how they are stored and to use a comparison function that is robust to all possibilities.
As a final side note
if (list[i].ssid == "MatchString") {
Since ssid is an array, you should know that when you do this comparison, you are not actually accessing the contents of ssid, but rather the address of the first element of ssid. When you pass list[i].ssid into strcmp (or strncmp), you are passing a pointer to the first element of the array in memory. The function then iterates over the entire array until it reaches the null character (in the case of strcmp) or until it has compared the specified number of elements (in the case of strncmp).
To match two strings use strcmp:
if (0==strcmp(str1, str2))
str1 and str2 are addresses to memory holding a null terminated string. Return value zero means the strings are equal.
In your case one of:
if (0==strcmp(list[i].ssid, AP_Match))
if (0==strcmp(list[i].ssid, "MatchString"))

Does strcmp in C++ check every value in a string if the second parameter is "0"?

If my string input is 1234567890, and I do the following:
(strcmp(input,"0"))
Will that return 1 if there is a 0 in my character array of 1234567890 and 0 if there isn't?
I know I can test this, and I did, and the answer is yes, but I'm not sure why and I can't find absolute specifics on strcmp.
No. strcmp returns 0 if the two strings are the same, non 0 otherwise.
Looks like you didn't even bother to google!
No, it compares two strings.
strcmp() returns 0 only if both strings are the same. Otherwise, the return value says something about the first non-matching character.
In your case, this has to do with the comparison between '1' and your '0'. It makes no difference that the other string has a '0' at the end.
strcmp() will typically check all characters from the first one until the last one or until there's a mismatch in the two strings.
The exact internal implementation of strcmp(), if you're asking about that, is not specified in the language standard. In theory, it could find lengths of the two strings and if they are equal, compare the strings using units bigger than char and even do that backwards.
strcmp() compares strings, not searches for one in the other. It returns 0 if the strings are identical. Otherwise it returns either a positive or a negative value, representing the sign of the difference between the first mismatching characters (the characters' values being treated as unsigned).
Does strcmp in C++ check every value in a string if the second
parameter is “0”
No it does not, strcmp() is a string compare function which checks if one string equals another. If it does, it returns 0 if one string is ordinally greater than the other, it returns 1 and returns -1 otherwise.
To check if it does exist, I suggest you write your own function for this.
//return 1 if if the character exists, 0 otherwise
int DoesCharExist(const char *pData, char character)
{
char *data = pData;
while(*data++){
if(*data == character) return 1;
}
return 0;
}