C++ сравнение строковых литералов
Я новичок в c++ (просто 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, но выполняются подряд я получаю другой ответ?
8 ответов:
вы сравниваете адреса памяти. По-видимому, ваш компилятор помещает строковые литералы в память в том порядке, в котором он их встречает, поэтому первый "меньше", чем второй.
поскольку в первом фрагменте он видит" A "первым и" Z "вторым," A " меньше. Поскольку он видит "Z" сначала во втором, "Z" меньше. В последнем фрагменте он уже имеет литералы "A" и "Z", размещенные при выполнении второй команды.
строковые литералы имеют статическую длительность хранения. Во всех этих сравнениях сравниваются адреса памяти, выделенные компилятором для строковых литералов. Кажется, что первый строковый литерал, с которым сталкивается компилятор, хранится в памяти с более низким адресом по сравнению со следующим встреченным строковым литералом.
таким образом в этой программе
int main() { cout << ("Z"< "A"); cout << ("A"< "Z"); }
строковый литерал "Z" был alllocated с более низким адресом, чем строковый литерал "A", потому что он был найден сначала компилятором.
примите во внимание это сравнение
cout << ("A"< "A");
может давать разные результаты в зависимости от параметров компилятора, поскольку компилятор может либо выделить два экстента памяти для строковых литералов, либо использовать только одну копию строковых литералов, которые являются одинаковыми.
из стандарта C++ (2.14.5 строковые литералы)
12 являются ли все строковые литералы различными (то есть хранятся в неперекрывающийся объекты) определяется реализация. Влияние попытка изменить строковый литерал не определена.
то же самое справедливо и для C.
в заявлении:
cout << ("A"< "Z");
вы создали 2 строковые литералы:
"A"
и"Z"
. Они относятся к типуconst char *
который является указателем на нулевой завершенный массив символов. Сравнение здесь заключается в сравнении указателей, а не значений, на которые они указывают. Это сравнение адресов памяти, что дает вам предупреждение компилятора. Результат сравнения будет определяться тем, где компилятор выделил память который будет несколько произвольным от компилятора к компилятору. В этом случае похоже, что первый найденный литерал получает первый адрес памяти вашим компилятором.так же, как в C, чтобы сравнить эти строковые литералы правильно, вам нужно использовать
strcmp
который будет делать сравнение значений.однако, когда вы делаете что-то более идиоматические с++ так делать:
cout << (std::string("A") < std::string("Z"));
тогда вы получите правильное сравнение значений, как этот оператор сравнения определен для
std::string
.
Если вы хотите сравнить фактические строки C++, вам нужно объявить строки C++:
int main() { const std::string a("A"); const std::string z("Z"); cout << (z < a) << endl; // false cout << (a < z) << endl; // true }
в C++ результаты не указаны. Я буду использовать N3337 для C++11.
во-первых, мы должны посмотреть, что такое тип строкового литерала.
§2.14.5
9
обычные строковые литералы и строковые литералы UTF-8 также являются называется узкими строковыми литералами. Узкий строковый литерал имеет тип "массив nconst char
", где n - это размер строки как определено ниже, и имеет статическую длительность хранения (3.7).массивы в разговорной речи говорят распад указатели.
§4.2
1
значение lvalue или rvalue типа " массивN T
" или "массив неизвестного граница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 в ответ.
вы сравниваете адреса памяти. В следующем примере объясняется, как сравнить 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; }
строковые константы ("A "и" Z") В C++ представлены C concept - массивом символов, где последний символ - '\0'. Такие константы должны сравниваться с типом функции strcmp ().
Если вы хотите использовать сравнение c++ std::string, вы должны явно указать его:
cout << (std::string( "A") < "Z");
строка представляет собой указатель на область памяти. Так что вы сначала сравните только адреса памяти с таким кодом
"Z"< "A"
сравнение строк выполняется с функциями. Они зависят от того," какая строка " у вас есть. У вас есть строки массива символов, но они также являются объектами. Эти объекты имеют другие функции сравнения. Например, CString в MFC имеет функцию Compare, но также и функцию CompareNoCase.
для ваших строк лучше всего использовать strcmp. Если вы отладка и шаг в вы видите, что делает функция: она сравнивает каждый символ обеих строк и возвращает целое число, если происходит первое различие или ноль, если то же самое.
int result = strcmp("Z", "A");
здесь вы найдете некоторые дополнительные пример кода