Why this code
if ("j" > "J")
return false, but this:
string a = "j";
string b = "J";
if (a > b)
return true? Which is the correct answer and how can i fix it?
That is happenig because "j" and "J" are const char []. For exampe "j" is array of chars that
c[0]='j' and c[1]='\0'. In C and C++ you can't compare two arrays.
it is better to use
strcmp("j","J");
witch is in
When you type
string a="j"
you run constructor in class string. But in class string you have overloaded operator< to compare two strings.
You can use single quotes to compare symbols: if ('j' > 'J')
This is because "j" and "J" are string literals, which are compared as const char pointers. The result of the comparison is therefore arbitrary, because the placement of literals in memory is implementation defined.
On the other hand, when you make std::string objects from these string literals, the < operator (along with other comparison operators) is routed to an override provided by the std::string class. This override does a lexicographic comparison of the strings, as opposed to comparing pointer values, so the results of comparison look correct.
You can try
if ("J" < "j")
and may be get a different result.
In fact "J" and "j" are constant C strings and may be placed on .data or .text sections which is determined by the output binary file format. So when you compare them, you are comparing their address in the memory.
But std::string is a C++ class which overloads the > operator, so it's not address/pointer comparing but content comparing.
Related
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"))
I have a vector of strings and I want to compare the first element of the vector with a bunch of different "strings".
Here is what i wanted to do:
if (strcmp(myString[0], 'a') == 0)
but strcmp doesnt work. I basically want to check the contents of myString[0] with a bunch of different characters to see if there is a match. So it would be something like
if (strcmp(myString[0], 'a') == 0){
}
else if (strcmp(myString[0], 'ah') == 0){
}
else ifif (strcmp(myString[0], 'xyz') == 0)
etc..
What can i use to do this comparison? Compiler complains about "no suitable conversion from std:string to "constant char*" exists so i know it doesnt like that im doing a string to char comparison, but i cant figure out how to correctly do this.
std::string overloads operator== to do a string comparison, so the equivalent to
if (strcmp(cString, "other string") == 0)
is
if (cppString == "other string")
So your code becomes (for example)
else if (myString[0] == "ah")
'a' is not a string, it is a character constant. You need to use "a", "ah", "xyz", etc.
Also, if you want to use strcmp, you need to use:
if (strcmp(myString[0].c_str(), "a") == 0)
You can also use the overloaded operator== to compare a std::string with a char const*.
if (myString[0] == "a")
You have marked this post as C++.
compare the first element of the vector with a bunch of different
"strings".
If I am reading your post correctly, the first element of the vector is a std::string.
std::string has a function and an operator to use for string-to-string comparison.
The function is used like:
if (0 == pfnA.compare(pfnB))
As described in cppreference.com:
The return value from std::string.compare(std::string) is
negative value if *this appears before the character sequence specified by the arguments, in lexicographical order
positive value if *this appears after the character sequence specified by the arguments, in lexicographical order
zero if both character sequences compare equivalent
The operator==() as already described, returns true when the two strings are the same.
I wanted to see if the Less Than operator (<) would work on strings. Well, it did. I started to experiment with it, and it turns out, I got the same result, regardless of the situtaion. The string on the left is always less than the string on the right, even if I swap the strings. Curious on why it did this, I tried to look up what the < operator actually does for strings. I read that it does a lexicographical comparison of the two strings. Still, this did not answer why my code was doing what it was doing. For example:
int main () {
if ("A" < "B")
std::cout << "Yes";
else
std::cout << "No";
return 0;
}
It would output Yes. That makes sense. But when I swap the strings:
int main () {
if ("B" < "A")
std::cout << "Yes";
else
std::cout << "No";
return 0;
}
It would still output Yes. I don't know if I am just being ignorant right now and not fully understanding what is happening here, or if there is something wrong.
It's because a string literal gives you a pointer to a read-only array containing the string (plus its terminator). What you are comparing are not the strings but the pointers to these strings.
Use std::strcmp if you want to compare C-style strings. Or use std::string which have overloaded comparison operators defined.
You are comparing the pointer to the string "A" with the pointer to the string "B".
If you want to compare just the value in the chars then use the single quote 'A' and 'B', if you want to compare strings then use the std::string class std::string("A") < std::string("B") or strcmp()
I'm taking in a string of input and putting it into an array, called complement, so that I can compare each element to "A", "G", "C", and "T" and make replacements to generate the complement of the DNA strand. I am trying to use this, but it doesn't work:
for(int i=0; i<x; i++){
if(complement[i] == "T")
complement[i] = "A";
I can't use the replace function because that goes through the entire array and does replacements altogether, but i need to go character by character so that AAGCT doesn't change A to T and then T back to A. I am doing this in C++, but any other language that could ease the situation would be ok. Thanks.
The reason is that you are comparing a Character with a String. 'A' != "A" one is a char and the other one is a pointer.
So what you have to do is
if (complement[i] == 'T')
I'm guessing that complement is declared something like
char complement[]
Which is to say an array of chars. If that is indeed the case, then
if(complement[i] == "T")...
doesn't do what you think it does.
More importantly,
complement[i] = "A";
here you are assigning a C-string literal to a char, which probably won't end well.
I suggest brushing up on your C, more specifically, arrays, chars, C-strings and pointers.
When comparing a string literal with another string literal with the == operator (or !=), is the result well defined?
For example, are the following guaranteed to hold?
assert("a" == "a");
assert("a" != "b");
Please don't say stuff like "use std::string" instead. I just want to know this specific case.
"a" == "a"
This expression may yield true or false; there are no guarantees. The two "a" string literals may occupy the same storage or they may exist at two different locations in memory.
I think that the closest language in the C++ Standard is: "Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementation defined" (C++11 ยง2.14.5/12). There are no other requirements or restrictions, so the result is left unspecified.
"a" != "b"
This expression must yield false because there is no way that these two string literals can occupy the same location in memory: "a"[0] != "b"[0].
When you compare string literals in this way, you are really comparing the pointers to the initial elements in the arrays.
Because we are comparing pointers, the relational comparisons (<, >, <=, and >=) are even more problematic than the equality comparisons (== and !=) because only a restricted set of pointer comparisons may be performed using the relational comparisons. Two pointers may only be relationally compared if they are both pointers into the same array or pointers into the same object.
If the two "a" string literals occupy the same location in memory, then "a" < "a" would be well-defined and would yield false, because both pointers point to the initial element ('a') of the same array.
However, if the two "a" string literals occupy different locations in memory, the result of "a" < "a" is undefined, because the two pointers being compared point into entirely unrelated objects.
Because "a" and "b" can never occupy the same location in memory, "a" < "b" always has undefined behavior. The same is true for the other relational comparison operators.
If you did, for some reason, want to relationally compare two string literals and have well-defined results, you can use the std::less comparer, which provides a strict-weak ordering over all pointers. There are also std::greater, std::greater_equal, and std::less_equal comparers. Given that string literals with the same contents may not compare equal, I don't know why one would ever want to do this, but you can.
The idea is that in C++ string literals are arrays. Since arrays do not have comparison operators defined for them, they are compared using the next best fit - the pointer comparison operator, as arrays will implicitly decay to pointers, so any comparison compares address and not content. Since "a" and "b" cannot be at the same memory location, "a" != "b" is a true assertion. It also forms a valid static assertion. No such guarantee can be made about "a" == "a", though GCC with -fmerge-constants (implied at -O1) can make a reasonably strong probability and -fmerge-all-constants can give you a guarantee (that potentially results in non-conforming behavior).
If you happen to want a content-based comparison, you can always use assert(!strcmp("a", "a")). Or, you can use some sort of constexpr based strcmp for a static assertion:
constexpr bool static_strequal_helper(const char * a, const char * b, unsigned len) {
return (len == 0) ? true : ((*a == *b) ? static_strequal_helper(a + 1, b + 1, len - 1) : false);
}
template <unsigned N1, unsigned N2>
constexpr bool static_strequal(const char (&str1)[N1], const char (&str2)[N2]) {
return (N1 == N2) ? static_strequal_helper(&(str1[0]), &(str2[0]), N1) : false;
}
static_assert(static_strequal("asdf", "asdf"), "no error - strings are equal");
static_assert(static_strequal("asdf", "jkl;"), "strings are not equal");
assert(!strcmp("asdf", "jkl;")); //no compile error - runtime error
//cannot use strcmp in static assert as strcmp is not constexpr...
Then, compile with g++ -std=c++0x (or -std=c++11 for gcc >= 4.7), and...
error: static assertion failed: "strings are not equal"