У меня есть этот вопрос на практическом экзамене для моего класса C ++, мы должны написать, что является выводом или если он выдает ошибку. Запуск этого кода вызывает ошибку сегментации, но кто-то может объяснить, почему? Это выглядит хорошо для меня.
string *s;
s = (string *) "This is my house. I have to defend it.";
cout << *s << endl;
4 ответа
Обращение через указатель типа std::string*
, когда он не указывает на объект типа std::string
, имеет неопределенное поведение.
Строковый литерал не является объектом типа std::string
. Строковый литерал представляет собой массив символов. std::string
- это класс, определенный в заголовке <string>
.
Запуск этого кода вызывает ошибку сегментации, но кто-то может объяснить, почему?
Вы косвенно через указатель, который не указывает на объект совместимого типа. Поведение вашей программы не определено.
Постскриптум Никогда не нужно использовать приведение в стиле C (например, (type)expression
). Он может легко подавлять полезные ошибки компиляции и заменять их неопределенным поведением. Этого следует избегать.
Если бы вы здесь не использовали приведение в стиле C, то система типов предупредила бы вас об ошибке перед запуском программы. В этом случае вы могли увидеть сообщение об ошибке, похожее на:
error: cannot convert 'const char [39]' to 'std::string*' {aka 'std::basic_string<char>*'} in assignment
Помогая вам понять, что типы не совпадают.
Вам необходимо узнать разницу между строковым литералом и классом std::string
.
Преобразование строкового литерала в std::string*
является неопределенным поведением. Это проявляется здесь как ошибка сегментации, когда код делает *s
, потому что s
недопустим.
Без этого приведения в стиле C (string *)
в s = (string *) "T...";
компилятор выдаст ошибку.
Всегда подвергайте сомнению эти приведения в стиле C в C ++.
Вероятная проблема (или, по крайней мере, одна из проблем) заключается в том, что у s нет выделенной памяти. Вам нужно использовать новое ключевое слово и попробовать что-то вроде этого:
string *s;
s = new string("This is my house. I have to defend it.");
cout << *s << endl;
Конечно, теоретически вам нужно использовать delete тоже.
Std :: string имеет тенденцию сводиться к чему-то похожему на это:
struct string
{
char* _begin;
char* _end;
char* _capacity;
};
Текстовая строка, которую вы определили, будет выглядеть так:
const char* const text = "This is my house. I have to defend it."
Итак, вы преобразуетесь из типа (char *) в тип (string *). Теперь это означает, что _begin будет хранить ячейку памяти «Это» , а _end будет хранить ячейку памяти «Мой дом» .
При печати строки в std :: cout она разыменует указатель на s и пытается найти размер строки, обычно реализуемый так:
size_t string::size() const { return _end - _begin; }
Учитывая, что _begin и _end не хранят значения указателя (это просто случайные биты текста), это приведет к тому, что cout попытается вывести очень неправильное количество символов _ (поскольку ячейки памяти в _begin и end являются нонсенс )
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .