1

I am using standard std::string variables which I try to compare. Quite strangely however, I am getting weird results:

string str1 = "44", str2 = "111";
bool smaller1 = str1.compare(str2) > 0;   // <- returns true, although should be false

bool smaller2 = "44" < "111";  // <- returns true, CORRECT

string str3(2, '4'), str4(3, '1');
bool small3 = str3 < str4;     // <- returns false, although should be true

I would expect since one string is shorter than the other, the lexacographical ordering should always give me true for "44" < "111".

The whole code looks like:

#include <iostream>
#include <string>

using namespace std;

int main() {

    string str1 = "44", str2 = "111";
    string str3(2, '4'), str4(3, '1');

    bool cmp1 = str1 < str2,
         cmp2 = "44" < "111",
         cmp3 = str3 < str4,
         cmp4 = str3.compare(str4) < 0;

    std::cout << "1: " << cmp1 << "\n";
    std::cout << "2: " << cmp2 << "\n";
    std::cout << "3: " << cmp3 << "\n";
    std::cout << "4: " << cmp4 << "\n";


    return 0;
}

and returns:

1: 0
2: 1
3: 0
4: 0

I am using g++ (GCC) 8.2.0 from MinGW 16.1 on Windows10. Am I missing something here? How can I force it to give me the correct results (shorter strings are smaller than longer). Thanks.

pisoir
  • 192
  • 3
  • 13
  • 3
    *"lexacographical ordering should always give me true for `"44"` < `"111"`"* Why should it? Since the first char of `"111"` is less than the first char of `"44"`, `"111"` is lexacographically less than `"44"`. Next, in `"44" < "111"` you compare pointers rather than strings. Since the pointers point to different unrelated obejcts that gives you undefined behavior. – HolyBlackCat Mar 24 '19 at 18:41
  • 3
    @HolyBlackCat That should be an answer, not just a comment. – Jeppe Stig Nielsen Mar 24 '19 at 18:43
  • 3
    Look in a dictionary. Does ”zoo” come before ”aardvark” or after? – molbdnilo Mar 24 '19 at 18:44
  • 1
    `"44" < "111"` is undefined behavior. You're likely comparing address values of string literals. – selbie Mar 24 '19 at 18:46
  • Hm. But don't we first compare the length of the strings? See e.g.: https://www.geeksforgeeks.org/comparing-string-objects-using-relational-operators-c/ – pisoir Mar 24 '19 at 18:47
  • @pisoir geeksforgeeks is not a good source for facts. – molbdnilo Mar 24 '19 at 18:48
  • If that page is typical of GeeksForGeeks, I would stop going to that website. – Eljay Mar 24 '19 at 18:48
  • @selbie. True. This is random result. – pisoir Mar 24 '19 at 18:50
  • @Eljay. Ok. But what about stackoverflow?;): https://stackoverflow.com/questions/13829434/using-the-less-than-comparison-operator-for-strings One of the examples in the answer is: "cat" < "caterpillar" EDIT: Aaa..because it starts with the same letter? – pisoir Mar 24 '19 at 18:52
  • Because it does a character-by-character comparison, and the first non-matching character (or when one runs out of letters) determines the order for `string`. But not for string literals, that just does a pointer comparison. – Eljay Mar 24 '19 at 18:56
  • 1
    From [cppreference.com](https://en.cppreference.com/w/cpp/string/basic_string/compare): _A character sequence consisting of count1 characters starting at data1 is compared to a character sequence consisting of count2 characters starting at data2 as follows. First, calculate the number of characters to compare, as if by size_type rlen = std::min(count1, count2). Then compare the sequences by calling Traits::compare(data1, data2, rlen). For standard strings this function performs character-by-character lexicographical comparison._ – Amadeus Mar 24 '19 at 18:57

1 Answers1

1
bool smaller2 = "44" < "111";  // <- returns true, CORRECT

No. You're just getting lukcy. That's comparing the addresses of string literals, not the same thing as an instance of an std::string. As a matter of fact, you could replace that expression in your code as "111" < "44" and it will likely return true if the compiler aligns the strings in memory in the same order as declared.

Correct way to compare strings lexicographical:

std::string str1 = "44";
std::string str2 = "111";
bool cmp1 = (str1 < str2);  // false, since '4' is greater than '1'

Correct way to compare strings as integers:

int val1 = std::stoi(str1);  // 44
int val2 = std::stoi(str2);  // 111
bool cmp2 = (val1 < val2);   // true since 44 is less than 111
selbie
  • 100,020
  • 15
  • 103
  • 173
  • Thanks. The problem with the stoi() is that I am comparing huge integers (that's why I have them as strings). If there is no simple way with strings, I will probably have to switch to some library for arbitrary length integers. – pisoir Mar 24 '19 at 19:05
  • 2
    @pisoir Compare the lengths first, then use `<` if they’re equal. – molbdnilo Mar 24 '19 at 19:10
  • but you will have problems with negative numbers – Amadeus Mar 24 '19 at 19:11
  • I don't care about negative numbers. @selbie, yes, I realized that as well. Thanks again. – pisoir Mar 24 '19 at 19:14