С++ Сравнение струнных литералов
Я новичок С++ (только oldschool c). Мой сын попросил о помощи в этом, и я не могу это объяснить. Если бы он спросил меня "как сравнить строки", я бы сказал ему использовать strcmp(), но это меня не смущает. Вот что он спросил:
int main()
{
cout << ("A"< "Z");
}
напечатает 1
int main()
{
cout << ("Z"< "A");
}
также напечатает 1, но
int main()
{
cout << ("Z"< "A");
cout << ("A"< "Z");
}
затем напечатает 10. Индивидуально оба оператора cout печатают 1, но выполняются в строке, я получаю другой ответ?
Ответы
Ответ 1
Вы сравниваете адреса памяти. По-видимому, ваш компилятор помещает строковые литералы в память в том порядке, в котором они встречаются, поэтому первый "меньше", чем второй.
Так как в первом фрагменте он видит "А" первым и "Z" второй, "А" меньше. Так как он видит "Z" сначала во втором, "Z" меньше. В последнем фрагменте у него уже есть литералы "A" и "Z", размещенные при второй команде.
Ответ 2
Строковые литералы имеют статическую продолжительность хранения. Во всех этих сравнениях сравниваются адреса памяти, выделенные компилятором для строковых литералов. Кажется, что первый строковый литерал, который встречается компилятором, хранится в памяти с более низким адресом по сравнению со следующим встреченным строковым литералом.
Таким образом, в этой программе
int main()
{
cout << ("Z"< "A");
cout << ("A"< "Z");
}
Строковый литерал "Z" был alllocated с более низким адресом, чем строковый литерал "A", потому что он был найден первым компилятором.
Учесть, что сравнение
cout << ("A"< "A");
может давать разные результаты в зависимости от параметров компилятора, потому что компилятор может либо выделять два экстента памяти для строковых литералов, либо использовать только одну копию строковых литералов, которые являются одинаковыми.
Из стандарта С++ (2.14.5 Строковые литералы)
12 Независимы ли все строковые литералы (то есть, хранятся в неперекрывающиеся объекты) определяется реализацией. Эффект попытка изменить строковый литерал undefined.
То же самое верно для C.
Ответ 3
В заявлении:
cout << ("A"< "Z");
Вы создали 2 строковые литералы: "A"
и "Z"
. Они имеют тип const char *
, который является указателем на нуль-завершенный массив символов. Здесь сравниваются указатели, а не значения, на которые они указывают. Это сопоставление адресов памяти здесь, что дает вам предупреждение о компиляторе. Результат сравнения будет определяться тем, где компилятор выделил память, которая будет несколько произвольной от компилятора к компилятору. В этом случае, похоже, первый найденный литерал получает ваш первый адрес памяти вашим компилятором.
Как и в C, чтобы правильно сравнить эти строковые литералы, вам нужно использовать strcmp
, который будет выполнять сравнение значений.
Однако, когда вы делаете что-то более идиоматическое С++, выполните:
cout << (std::string("A") < std::string("Z"));
Затем вы получите правильное сравнение значений, поскольку этот оператор сравнения определен для std::string
.
Ответ 4
Если вы хотите сравнить фактические строки С++, вам нужно объявить строки С++:
int main()
{
const std::string a("A");
const std::string z("Z");
cout << (z < a) << endl; // false
cout << (a < z) << endl; // true
}
Ответ 5
В С++ результаты не заданы. Я буду использовать N3337 для С++ 11.
Сначала мы должны посмотреть, что такое тип строкового литерала.
§2.14.5
9
Обычные строковые литералы и строковые литералы UTF-8 также называемые узкими строковыми литералами. Узкий строковый литерал имеет type "array of n const char
", где n - размер строки как определено ниже, и имеет статическую продолжительность хранения (3.7).
Массивы говорят, что они распадаются на указатели.
§4.2
1
Значение lvalue или rvalue типа "массив N T
" или "массив неизвестных bound of T
" может быть преобразован в prvalue типа "указатель на T
". Результатом является указатель на первый элемент массива.
Поскольку ваши строковые литералы содержат один символ, они одного типа (char[2]
, включая нулевой символ.)
Поэтому применяется следующий параграф:
§5.9
2
[...]
Указатели на объекты или функции того же типа (после указателя преобразования), с результатом, определяемым следующим образом:
[...]
- Если два указателя p
и q
того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов тот же массив или разные функции, или если только один из них является нулевым, результаты p<q
, p>q
, p<=q
и p>=q
не определены.
Unspecified означает, что поведение зависит от реализации. Мы видим, что GCC предупреждает об этом:
warning: comparison with string literal results in unspecified behaviour [-Waddress]
std::cout << ("Z" < "A");
Поведение может измениться в настройках компиляторов или компилятора, но на практике, что происходит, см. Wintermute answer.
Ответ 6
Вы сравниваете адреса памяти. В следующем примере объясняется, как сравнить 2 строки:
#include "stdafx.h"
#include <iostream>
#include <cstring> //prototype for strcmp()
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
cout << strcmp("A", "Z"); // will print -1
cout << strcmp("Z", "A"); // will print 1
return 0;
}
Ответ 7
Строковые константы ( "A" и "Z" ) в С++ представлены концепцией C - массивом символов, где последний символ "\ 0". Такие константы следует сравнивать с типом функции strcmp().
Если вы хотите использовать сравнение С++ std::string, вы должны явно указать его:
cout << (std::string( "A") < "Z");
Ответ 8
Строка представляет указатель на область памяти. Поэтому вы сначала сравниваете только адреса памяти с таким кодом
"Z"< "A"
Сравнение строк выполняется с помощью функций. Они зависят от "какой строки" у вас есть. У вас есть строки массива char, но они также являются объектами. Эти объекты имеют другие функции сравнения. Например, CString в MFC имеет функцию Compare, а также функцию CompareNoCase.
Для ваших строк лучше всего использовать strcmp. Если вы отлаживаете и входите в систему, вы видите, что делает функция: она сравнивает каждую char обеих строк и возвращает целое число, если происходит первое различие, или ноль, если то же самое.
int result = strcmp("Z", "A");
Здесь вы найдете еще пример кода