сравнение между строковым литералом
-
20-09-2019 - |
Вопрос
Этот очень простой код:
#include <iostream>
using namespace std;
void exec(char* option)
{
cout << "option is " << option << endl;
if (option == "foo")
cout << "option foo";
else if (option == "bar")
cout << "opzion bar";
else
cout << "???";
cout << endl;
}
int main()
{
char opt[] = "foo";
exec(opt);
return 0;
}
сгенерируйте два предупреждения:сравнение со строковым литералом приводит к неопределенному поведению.
Можете ли вы объяснить, почему именно этот код не работает, но если я изменю
char opt[]
Для
char *opt
это работает, но выдает предупреждение?Связано ли это с завершением \0?В чем разница между двумя объявлениями opt?Что, если я использую квалификатор const?Решение состоит в том, чтобы использовать std::string?
Решение
массивы символов или указатели на символы на самом деле не то же самое, что объекты класса string в C ++, так что это
if (option == "foo")
Не сравнивает строку option
к строковому литералу "foo" он сравнивает адрес из option
с адресом строкового литерала "foo".Вам нужно использовать одну из многих функций сравнения строк, если вы хотите знать, совпадает ли опция с "foo". strcmp
это очевидный способ сделать это, или вы можете использовать std::string
вместо того , чтобы char*
Другие советы
Вы можете использовать ==
оператор для сравнения строк, только если вы используете std::string
(что является хорошей практикой).Если вы используете строки char*/char[] в стиле C, вам необходимо использовать функции C strcmp
или strncmp
.
Вы также можете использовать std::string::operator ==
для сравнения std::string
со строкой C:
std string foo = "foo";
const char *bar = "bar";
if (foo == bar)
...
Причина, по которой это не работает, заключается в том, что при сравнении сравниваются не строки, а указатели на символы.
Причина , по которой это мочь работа при использовании char * заключается в том, что компилятор может решить сохранить литеральную строку "opt" один раз и повторно использовать ее для обеих ссылок (я уверен, что где-то видел настройку компилятора, которая указывает, делает ли это компилятор).
В случае char opt[] компилятор копирует строковый литерал в область хранения, зарезервированную для массива opt (вероятно, в стеке), что приводит к тому, что указатели будут разными.
Ренце
Похоже, вы пришли из Java / C # :) В C ++ строка - это просто указатель на память, где хранятся символы, и с нулевым символом в конце.Если строки "выглядят" равными, они могут указывать на разные области в памяти и не будут равны.чтобы проверить равенство, используйте либо класс C ++ std::string, либо C-функцию strcmp .
Для C ++ я бы использовал std::string решение:
#include <iostream>
#include <string>
using namespace std;
void exec(string option)
{
cout << "option is " << option << endl;
if (option == "foo")
cout << "option foo";
else if (option == "bar")
cout << "option bar";
else
cout << "???";
cout << endl;
}
int main()
{
string opt = "foo";
exec(opt);
exec("bar");
char array[] = "other";
exec(array);
return 0;
}
std::string знает, как создать себя из char[], char * и т.д., так что вы все равно можете вызвать функцию и этими способами.