У меня есть этот вопрос на практическом экзамене для моего класса C ++, мы должны написать, что является выводом или если он выдает ошибку. Запуск этого кода вызывает ошибку сегментации, но кто-то может объяснить, почему? Это выглядит хорошо для меня.

    string *s;
    s = (string *) "This is my house. I have to defend it.";
    cout << *s << endl;
c++
0
Jack 3 Май 2019 в 04:25

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

Помогая вам понять, что типы не совпадают.

4
eerorika 3 Май 2019 в 01:40

Вам необходимо узнать разницу между строковым литералом и классом std::string.

Преобразование строкового литерала в std::string* является неопределенным поведением. Это проявляется здесь как ошибка сегментации, когда код делает *s, потому что s недопустим.

Без этого приведения в стиле C (string *) в s = (string *) "T..."; компилятор выдаст ошибку.

Всегда подвергайте сомнению эти приведения в стиле C в C ++.

1
Maxim Egorushkin 3 Май 2019 в 01:41

Вероятная проблема (или, по крайней мере, одна из проблем) заключается в том, что у s нет выделенной памяти. Вам нужно использовать новое ключевое слово и попробовать что-то вроде этого:

string *s;
s = new string("This is my house. I have to defend it.");
cout << *s << endl;

Конечно, теоретически вам нужно использовать delete тоже.

0
Chipster 3 Май 2019 в 03:15

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 являются нонсенс )

-1
robthebloke 3 Май 2019 в 01:35