Страницы

Поиск по вопросам

суббота, 23 марта 2019 г.

char * и const char *

Решил вернуться к СИ и прочитать книгу K&R, и вот опять споткнулся на теме указателей, по логике вроде все понятно, но вот именно с char * и const char * какие-то проблемы.
Давайте я приведу код и покажу что мне все такие не ясно!
Пример 1:
char *pstr = "Hello, world"; *pstr = 'D'; /// При запуске приложения на этом месте вылетит сбой не понятно! printf(pstr); /// Ну и конечно ничего не выведет, измененную строку я не получу, ой точнее массив из символов
Пример 2:
const char *pstr = "Hello, world"; *pstr = 'D'; /// Сбоя не будет и программа вообще не скомпилируется т.к компилятор сообщит что мы не можем изменять наш константный объект printf(pstr); /// До сюда дело не дойдет
Пример 3:
char str[] = "Hello, world"; char *pstr = str; *pstr = 'D'; /// Все ок мы успешно поменяем наш первый элемент массива printf(pstr); /// Мы получим это: "Dello, world"
Подведем черту над всеми этими примерами: Почему я не могу в первом примере поменять отдельно каждый литерал? (Я же не объявлял объект константным как во втором примере)
P.S Третий пример привел для общей картины чтобы показать что все работает если ввести дополнительный параметр


Ответ

В первом и втором случае вы работаете напрямую со строковым литералом.
В языке С у вас нет никакого контроля над const-квалификацией типа строкового литерала. Эта const-квалификация однозначно определяется языком. Тип строкового литерала в C - char [N]. И несмотря на то, что тип строкового литерала формально не содержит квалификатора const, строковый литерал тем не менее является неизменяемым (немодифицируемым) объектом. Попытки изменения строкового литерала, как и любого другого немодифицируемого объекта, ведут к неопределенному поведению.
Как вы объявляли свой указатель pstr - c const или без - на тип и свойства строкового литерала никакого влияния не оказывает. Ваш указатель не имеет никакого отношения к строковому литералу, как таковому. Ваш указатель - это не более чем путь доступа (access path) к реальному объекту. Константность пути доступа - это не более чем элемент самодисциплины, который в общем случае не связан с константностью объекта, к которому этот путь ведет. Язык С предоставляет вам средства для легального создания как константных путей доступа к модифицируемым объектам, так и неконстантных путей доступа к немодифицируемым объектам
int a = 42; const int *pa = &a; // константный путь доступа к модифицируемому объекту
const int b = 5; int *pb = (int *) &b; // неконстантный путь доступа к немодифицируемому объекту
В конечном итоге возможность легальной модификации объекта определяется именно и только модифицируемостью самого объекта и никак не зависит от константности пути доступа к нему (ибо последняя легко устранима).
Учитывая, что литерал является неизменяемым объектом, указывать на строковые литералы неконстантным указателем (как в вашем первом примере) никакого смысла нет, даже если язык и позволяет формально это делать.
В третьем варианте вы не работаете со строковым литералом напрямую, а создаете собственный модифицируемый массив, который только инициализируется значением строкового литерала. Т.е. ваш массив содержит самостоятельную копию значения строкового литерала. Это ваш собственный массив и вы можете модифицировать его как угодно.

Комментариев нет:

Отправить комментарий