2014-12-12 3 views
60

Я новичок C++ (только oldschool c). Мой сын попросил о помощи в этом, и я не могу это объяснить. Если бы он спросил меня «как сравнить строки», я бы сказал ему использовать strcmp(), но это меня не смущает. Вот что он спросил:C++ Сравнение литералов строк

int main() 
{ 
    cout << ("A"< "Z"); 
} 

напечатает 1

int main() 
{ 
    cout << ("Z"< "A"); 
} 

также напечатает 1, но

int main() 
{ 
    cout << ("Z"< "A"); 
    cout << ("A"< "Z"); 
} 

будет печатать 10. Индивидуально оба утверждения COUT печати 1, но выполнен в строке я получаю другой ответ?

+4

на самом деле не ваш вопрос, но вы могли бы заставить его работать путем преобразования либо буквальным в 'станд :: string':' станд :: COUT << (Std :: string ("A") <"Z"); ' –

+0

FYI cstrings можно преобразовать в строки C++, а затем сравнить с типичными операторами. 'std :: string s1 =" A ";' etc –

+11

Или поскольку C++ 14 просто '(" A "s <" Z "s)'. – Snps

ответ

86

Вы сравниваете адреса памяти. По-видимому, ваш компилятор помещает строковые литералы в память в том порядке, в котором они встречаются, поэтому первый «меньше», чем второй.

Поскольку в первом фрагменте он видит «А» первым и «Z» второй, «А» меньше. Так как он видит «Z» сначала во втором, «Z» меньше. В последнем фрагменте у него уже есть литералы «A» и «Z», размещенные, когда вторая команда катится.

+0

Яркая мышь, может быть? Случается. – Wintermute

+1

Возможно, вам стоит упомянуть метод ['compare'] (http://en.cppreference.com/w/cpp/string/basic_string/compare), чтобы фактически сравнить их. – tadman

+24

Я думаю, что стоит отметить, что это точно так же, как в «oldschool c». –

19

Строковые литералы имеют статическую продолжительность хранения. Во всех этих сравнениях сравниваются адреса памяти, выделенные компилятором для строковых литералов. Кажется, что первый строковый литерал, который встречается компилятором, хранится в памяти с более низким адресом по сравнению со следующим встреченным строковым литералом.

Таким образом, в этой программе

int main() 
{ 
    cout << ("Z"< "A"); 
    cout << ("A"< "Z"); 
} 

строка «Z» была alllocated с более низким, чем адресом строка буквальной «А», потому что он был найден первым компилятором.

Примите во внимание, что сравнение

cout << ("A"< "A"); 

может дать разные результаты в зависимости от опций компилятора, так как компилятор может либо выделить два экстента памяти для строковых литералов или использовать только один экземпляр строковых литералов то же самое.

От стандарта C++ (2.14.5 Строковые литералы)

12 ли все строковые литералы различны (то есть, которые хранятся в объектов непересекающихся) определяется реализацией. Эффект , пытающийся изменить строковый литерал, не определен.

То же самое справедливо для C.

+4

Стоит отметить, что это не строки типа C++ 'std :: string', а строки' char * 'C-style. – tadman

7

Если вы хотите сравнить фактические C строки ++, вам нужно объявить C++ строки:

int main() 
{ 
    const std::string a("A"); 
    const std::string z("Z"); 

    cout << (z < a) << endl; // false 
    cout << (a < z) << endl; // true 
} 
13

В заявлении:

cout << ("A"< "Z"); 

Вы создали 2 string literals: "A" и "Z". Они имеют тип const char *, который является указателем на массив символов с нулевым завершающим символом.Здесь сравниваются указатели, а не значения, на которые они указывают. Это сравнение адресов памяти здесь, что дает вам предупреждение о компиляторе. Результат сравнения будет определяться тем, где компилятор выделил память, которая будет несколько произвольной от компилятора к компилятору. В этом случае похоже, что первый найденный литерал получает ваш первый адрес памяти от вашего компилятора.

Как и в C, чтобы правильно сравнить эти строковые литералы, вам необходимо использовать strcmp, который будет выполнять сравнение значений.

Однако, когда вы делаете что-то более идиоматических C++ путь, выполнив:

cout << (std::string("A") < std::string("Z")); 

Тогда вы получите правильное сравнение значений как оператор сравнения определен для std::string.

7

В C++ результаты не заданы. Я буду использовать N3337 для C++ 11.

Во-первых, мы должны посмотреть, что такое тип строкового литерала.

§2.14.5

9 Обычных строковые литералы и UTF-8, строковые литералы также называют узкие строковые литералы. Узкая строка символов имеет типа «массив нconst char», где п является размером строки , как определено ниже, и имеет статический срок хранения (3.7).

Массивы просторечии называется распада к указателям.

§4.2

1 Именующее выражение или 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-х answer.

0

Вы сравниваете адреса памяти. Пример, который следуют объясняет, как сравнить 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; 
} 
0

строковые константы («A» и «Z») в C++ представлены концепции C - массив символов, где последний символ «\ 0 ». Такие константы следует сравнивать с типом функции strcmp().

Если вы хотели бы использовать C++ сравнение станд :: строка вы должны явно указать это:

cout << (std::string("A") < "Z"); 
0

Строка, представляющая указатель на область памяти. Таким образом, вы сначала сравниваете только адреса памяти с таким кодом

"Z"< "A" 

сравнение строк выполняется с функциями. Они зависят от «какой строки» у вас есть. У вас есть строки массива символов, но они также являются объектами. Эти объекты имеют другие функции сравнения. Например, CString в MFC имеет функцию Compare, а также функцию CompareNoCase.

Для ваших строк лучше всего использовать strcmp. Если вы отлаживаете и входите в систему, вы видите, что делает функция: она сравнивает каждый символ обеих строк и возвращает целое число, если происходит первое различие, или ноль, если это то же самое.

int result = strcmp("Z", "A"); 

Здесь вы найдете некоторые дополнительные sample code

 Смежные вопросы

  • Нет связанных вопросов^_^