Урок 84. Символьные константы строк C-style

   ⁄ 

 Обновлено 29 Сен 2017

  ⁄   

В 79 уроке мы узнали, как создать и инициализировать строку C-style:

C++ поддерживает еще один способ создания символьных констант строк C-style — через указатели:

Хотя обе эти программы работают и производят одинаковые результаты, распределение памяти в них выполняется несколько иначе.

В первом случае программа выделяет память для фиксированного массива длиной 5 и инициализирует эту память строкой «Alex\0». Поскольку память была специально выделена для массива — мы можем изменять его содержимое. Сам массив рассматривается как обычная локальная переменная, поэтому, когда он выходит из области видимости, память, используемая им, освобождается для других объектов.

Что происходит в случае с символьной константой? Компилятор помещает строку «Alex\0» в память типа read-only (только чтение), а затем создает указатель, который указывает на эту строку. Несколько строковых литералов с одним и тем же содержимым могут указывать на один и тот же адрес. Поскольку эта память доступна только для чтения, а также то, что внесение изменений в строковый литерал может повлиять на другие использования этого литерала — лучше всего перестраховаться, объявив строку константой (типа const). Также, поскольку строки, объявленные таким образом, существуют на протяжении всей жизни программы (они имеют статическую продолжительность, а не автоматическую, как большинство других локально определенных литералов), нам не нужно беспокоиться о проблемах, связанных с областью видимости. Поэтому, следующее в порядке вещей:

В коде выше getName() возвращает указатель на строку C-style “John”. Всё хорошо, так как “John” не выходит из области видимости, когда getName() завершает свое выполнение, поэтому вызывающий объект все равно имеет доступ к строке.

Правило: При использовании символьных констант строк Cstyle в вашей программе всегда делайте их const!

std::cout и указатели типа char

На этом этапе вы, возможно, уже успели заметить то, как std::cout обрабатывает указатели разных типов.

Рассмотрим следующий пример:

Результат на компьютере автора:

0046FAE8
Hello!
John

Почему в массиве типа int выводится адрес, а в массивах типа char — строки?

Дело в том, что при передаче указателя не типа char, в результате выводится просто содержимое этого указателя (адрес памяти). Однако, если вы передадите объект типа char* или const char*, то std::cout предположит, что вы намереваетесь вывести строку. Следовательно, вместо вывода значения указателя – выведется строка, на которую тот указывает!

Хотя это всё замечательно в 99% случаев, но это может привести и к неожиданным результатам. Например:

Здесь мы намереваемся вывести адрес переменной a. Тем не менее, &a имеет тип char*, поэтому std::cout выведет это как строку! Результат на компьютере автора:

R╠╠╠╠╜╡4;¿■A

Почему так? std::cout предположил, что &c (типа char*) является строкой. Поэтому сначала вывелось «R», а затем вывод продолжился. Следующим в памяти был мусор. В конце концов, std::cout столкнулся с ячейкой памяти, имеющей значение 0, которое он интерпретировал как нуль-терминатор, и, соответственно, остановил вывод. То, что вы видите в результате, может отличаться в зависимости от того, что находится в памяти после переменной a.

Подобное вряд ли случится с вами в реальной жизне (так как вряд ли вы захотите выводить адреса памяти), но это хорошая демонстрация того, как всё работает под капотом и как программы могут случайно сойти с рельсов.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (6 оценок, среднее: 5,00 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *