Сравнение указателей
Почему в следующем коде
int main(int argc, char* argv[])
{
char* a = (char*)"string";
char* b = (char*)"string";
if (a == b) std::cout << "Hello world";
return 0;
}
При сравнении мы получаем положительный результат? По идеи, мы сравниваем указатели, разве не так?
Но если объявить массив, то все должно правильно работать
int main(int argc, char* argv[])
{
char a[] = "string";
char b[] = "string";
if (a == b) std::cout << "Hello world";
return 0;
}
Тут уже не выведет сообщение. Почему так выходит?
Ответы (3 шт):
Потому что в первом примере вы присваиваете так называемый строковый литерал "string" в указатель, причём два раза в разные указатели. У вас два указателя ссылаются на один и тот же литерал. Во втором примере вы создаёте массив из char'ов, а под него компилятором выделяется статическая память, куда данная строка копируется.
Возьмем, например, Visual C++ 2019 и скомпилируем первый код
test.cpp
#include <iostream>
int main()
{
char* a = (char*)"string";
char* b = (char*)"string";
if (a == b) std::cout << "Hello world";
}
следующим образом:
cl /EHsc test.cpp
Результат — никакого вывода на экран... Добавим ключик /GF:
cl /EHsc /GF test.cpp
и получим приветствие. И первое, и второе поведение вполне допустимы, потому что стандарт ничего не говорит о том, где именно хранятся строковые литералы. Даже не надо все эти переменные и приведения, достаточно кода
std::cout << ("a" == "a");
Так что в определенном смысле вопрос основан на неверной посылке... По сути, основываясь на представлении о равенстве/неравенстве указателей двух строковых литералов мы получаем в некотором смысле неопределенное поведение (не говоря уж об UB, вызванном приведением строкового литерала к типу char*).
А вот во втором случае дела обстоят совсем иначе, потому что здесь
char a[] = "string";
char b[] = "string";
имеются два разных массива в памяти, а строка — не более чем инициализатор... Изменяя содержимое a, вы никак не меняете тем самым содержимое b. Так что и адреса их различны.
Строковые литералы с одинаковым текстом могут иметь одинаковые адреса, а могут и не иметь - это зависит от компилятора.
Whether all string-literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.
А во втором примере вы сравниваете не литералы, а обычные массивы, созданные из них. На них (как и на остальные объекты) это исключение не действует, и они обязаны иметь разные адреса.