С++ Сравнение струнных литералов

Я новичок С++ (только 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");

Здесь вы найдете еще пример кода