Сравнение String Elements vs Strings
Следующий код печатает
1
0
И мне было интересно, почему значения разные, если сравнения используют одну и ту же строку... Я некоторое время боролся с этим и не могу понять, почему они возвращают разные логические значения.
int main()
{
string stringArray[] = { "banana","Banana","zebra","apple","Apple","Zebra","cayote" };
cout << (stringArray[1] < stringArray[0]) << endl;
cout << ("Banana" < "banana") << endl;
return 0;
}
Ответы
Ответ 1
stringArray[n]
является std::string
, но "Banana"
является строковым литералом (массив из char
s).
Когда вы выполняете "Banana" < "banana"
, оба строковых литерала неявно преобразуются в указатели char
, указывающие на массив char
. <
затем сравнивает эти адреса памяти.
Ответ 2
"Banana" < "banana"
не сравнивает содержимое строк. Это сравнение указателей, для которых "Banana"
и "Banana"
разрешено.
Чтобы сравнить строки cstyle без их преобразования в std::string
, вы можете использовать strcmp()
.
Ответ 3
string stringArray[] = { "banana","Banana","zebra","apple","Apple","Zebra","cayote" };
Это означает, что вы получаете кучу объектов std::string
, созданных из char const*
, полученных из отдельных строковых литералов.
Рассмотрим одиночную инициализацию std::string
:
std::string s = "...";
Литерал справа имеет тип char const[4]
. Он "распадается" на char const*
, используемый конструктором std::string
.
То же самое происходит, когда вы инициализируете массив объектов std::string
из строковых литералов.
cout << (stringArray[1] < stringArray[0]) << endl;
Для std::string
использование оператора <
означает лексикографическое сравнение. Поэтому это использует лексикографическое сравнение и имеет ожидаемый результат.
cout << ("Banana" < "banana") << endl;
В этом случае не участвует std::string
. Вы сравниваете два char const[7]
друг с другом.
Что это значит? Как оказалось, совершенно другая вещь. Оба массива "распадаются" на char const*
до их первого элемента. Результатом сравнения двух несвязанных указателей с <
является неуказанный. Вам посчастливилось получить 0 в результате, потому что вы также можете получить 1 и не заметить ошибку. Компиляторы также могут генерировать предупреждение для этого, например:
warning: comparison with string literal results in unspecified behaviour
Итак, как вы можете видеть, эта операция не имеет абсолютно никакого отношения к лексикографическому сравнению.
Один из способов решения этой проблемы - повернуть хотя бы один из операндов в std::string
:
cout << (string("Banana") < "banana") << endl;
A <
сравнение между std::string
и a char const*
(или наоборот) определяется как лексикографическое.