Что такое const char в c
Что такое const char в c
В действительности, в соответствии со стандартом на языки C и C++ (правило чтения операторов «Read Declarations Right-to-Left«, т. е. надо читать всегда оператор справа налево), модификатор const влияет на элемент, слева от которого стоит const. Поэтому если использовать const перед типом, то это фактически ничего не значит, и используется просто для удобства запоминания.
К примеру, следующие два оператора совершенно эквивалентны:
Оба указателя УказательНаНеизменяемоеСодержимое1 и УказательНаНеизменяемоеСодержимое2 указывают на строку, являющуюся константой, и оба эти указателя можно модифицировать runtime в коде программы.
Если же Вы хотели получить от указателя другое, чтобы это был постоянный указатель, который нельзя модифицировать, то нужно поместить const после звездочки (тогда получится наоборот, строка может быть изменяемой, а сам указатель изменить нельзя):
Чтобы защитить от изменения как сам указатель, так и содержимое, на которое он указывает, то нужно использовать два ключевых слова const:
[Примеры ключевого слова const при использовании с указателями]
В этом простом примере если мы попробуем в коде присвоить значение переменной j, то это будет обнаружено на этапе компиляции программы, компилятор выдаст ошибку.
Указатель на константу. Когда ключевое слово const используется с указателями, то важно помнить, что реальный смысл определения зависит от положения ключевого слова const.
Указатель на константу указывает на данные, которые должны быть постоянными. Это просто означает, что мы не можем поменять данные, на которые ссылается указатель. Вот несколько примеров кода, иллюстрирущие то, что мы подразумеваем указателем на константу:
Постоянный указатель. В таком указателе находящийся в нем адрес является константой. Но сама переменная, на которую ссылается указатель может быть изменена, т. е. она может не являться константой. Вот несколько примеров:
Постоянный указатель на константу. Можно думать об этом случае как о комбинации двух примеров выше. Т. е. нельзя поменять ни сам адрес (значение указателя), ни данные, на которые он указывает. Пример:
[Ссылки]
Комментарии
Но позвольте, вы же говорите что const влияет только на содержимое слева от const, а сами используете const самым левым (т.е. не влияющим ни на что).
/*const int j = 10;
В этом простом примере если мы попробуем в коде присвоить значение переменной j, то это будет обнаружено на этапе компиляции программы, компилятор выдаст ошибку.» */
Присваивание символа const char *
Добрый день, хочу расставить точки над «i» для себя.
Вопрос в следующем. Почему, когда мы const char * присваиваем строку, он присваивает, а символ — нет? Может, где-то для const char * перегружен оператор присваивания, и он ему присваивает новый адрес? А при присваивании литерала мы пытаемся записать по тому же адресу?
3 ответа 3
Вопрос в следующем. Почему, когда мы const char * присваиваем строку, он присваивает, а символ — нет?
Нужно различать константный указатель и указатель на константу.
1) Указатель на константу: нельзя менять содержимое объекта, на который указывает указатель, но можно менять содержимое самого указателя (указатель — это переменная, содержащая адрес другой переменной).
2) Константный указатель: можно менять содержимое объекта, но нельзя менять значение самого указателя. Проще говоря, указатель нельзя переназначить на другой объект, но сам указатель поменять можно.
3) Константный указатель на константу: совокупность первых двух.
После присваивания const char *c = «123»; в c храниться некий адрес, по которому размещена строка «123». Компилятор обычно размещает ее в памяти, которая «read only» (записать то можно туда, просто операционная система знает, что это неправильно и пресекает попытки записи). Но так как использовать будет только для чтения, то все нормально.
Строка c[2] = ‘5’; пытается записать в эту неизменяемую память. Память только для чтения.
Почему так сделано? для оптимизаций и упрощения. Пусть в Вашей программе есть ещё десять мест, где есть константа «123». Компилятор не будет создавать 11 копий, а будет использовать один и тот же адрес. А теперь представьте, что вышеуказанное изменение разрешено:).
Старые компиляторы этого не делали и часто наблюдались интересные спецэффекты, когда константы изменяли свое значение.
Но компилятор может поступить и по другому.
в этом случае может даже выбросить переменную test, а ее значение вывести непосредственно.
Учебник по программированию на С++ говорит, что:
Официальный тип строковых литералов, таких как «Привет»,- const char []. Строка «Привет» имеет тип const char [7]. Секундочку! Ведь в слове Привет шесть букв, а не семь! Не переживайте, ошибки здесь нет. Дополнительный элемент содержит завершающий пустой символ, ‘ \0’ (значение 0), который сообщает компьютеру длину строки. В конце каждого строкового литерала есть скрытый пустой символ (\0), который позволяет алгоритмам определять длину строки и факт достижения конца строки. Длина строки нужна не всем алгоритмам, но большинству из них. Присвоить строковый литерал переменной типа char* можно следующим образом:
Однако со значением, на которое указывает х, нельзя работать. Если оно не будет постоянным, возникнет ошибка, как в следующем примере:
Этот код вызывает ошибку, потому что нельзя изменять значение константы. Чтобы получить строку, которую можно изменять, следует присвоить строковый литерал строковому объекту или символьному массиву. Пример объявления символьного массива, элементы которого могут изменяться:
С этим кодом все в порядке, а новым значением строки будет «Тривет». Многие из стандартных библиотечных функций С принимают в качестве одного из аргументов значение типа char*. Однако если строка хранится в виде указателя на символ, ее длина не может быть определена, как в случае строковых литералов, завершаемых пустым символом. В отсутствие пустого символа невозможно понять, где кончается строка.
Разница между char* и const char*?
в чем разница между
что указывает на постоянный строковый литерал и
9 ответов
char* Это mutable указатель на mutable символ/строку.
const char* это mutable указатель на неизменяемые символ/строку. Вы не можете изменить содержимое местоположения, на которое указывает этот указатель. Кроме того, компиляторы должны выдавать сообщения об ошибках при попытке сделать это. По той же причине, преобразование из const char * to char* устарела.
char* const это неизменяемые указатель (он не может указывать на любое другое место)но содержимое местоположение точки mutable.
const char* const это неизменяемые указатель на неизменяемые символ/строку.
вы можете изменить символ, который name указывает, а также символ, на который он указывает.
EDIT:
из комментариев ваш вопрос, похоже, спрашивает о разнице между двумя объявлениями, когда указатель указывает на строковый литерал.
в этом случае не должен изменить символ, к которому name баллов, так как это может привести к неопределено Поведение. Строковые литералы могут быть выделены в областях памяти только для чтения (реализация определена), и пользовательская программа не должна изменять его в любом случае. Любая попытка сделать это приводит к неопределенному поведению.
так что единственная разница в этом случае (использования со строковыми литералами) заключается в том, что второе объявление дает вам небольшое преимущество. Компиляторы обычно дают вам предупреждение, если вы попытаетесь изменить строковый литерал во втором случай.
выход:
cc1: предупреждения рассматриваются как ошибки
еда.c: в функции ‘ main’:
еда.c: 9: ошибка: передача аргумента 1 ‘strcpy’ отбрасывает квалификаторы из целевого типа указателя
обратите внимание, что компилятор предупреждает о втором случае, но не о первом.
C++ поддерживает две нотации неизменности:
constexpr функция должна быть достаточно простой, чтобы вычисляться компилятором, а также возвращать вычисленное значение. constexpr функции могут вызываться неконстантыми аргументами в контексте которых не требуются константные выражения.
const
Объекты со спецификатором const не могут быть изменены, а также должны быть инициализированы.
Поскольку объекты со спецификаторов const не могут быть изменены, то следующий код будет ошибочным:
Обратите внимание, что const изменяет тип объекта, а не указание того, как должна быть назначена переменная. const ограничивает способы работы с объектом.
При использовании указателя задействуются два объекта: сам указатель и объект, на который указывает. Префиксное’ объявление указателя с const делает константным объект, а не указатель. Чтобы объявить как const сам указатель, а не объект, на который он указывает, необходимо поместить const после символа указателя. Например:
Местоположение const относительно базового типа не принципиально, поскольку не существует типа данных const*. Принципиальным является положение const относительно символа *. Поэтому возможны следующие записи:
Первая версия используется для строк, элементы которых не должны быть изменены функцией и возвращает указатель на const, который не позволяет изменять результат. Вторая версия используется для изменяемых строк.
Вы можете назначить адрес неконстантной переменной указателю на константу, потому что это не может нанести никакого вреда. Однако адрес константы нельзя назначить неконстантному указателю, поскольку это позволит изменить значение объекта. Например:
constexpr
Константное выражение является выражением, которое вычисляется во время компиляции. Константные выражения не могут использовать значения и переменные, которые не известны во время компиляции.
Существует множество причин, по которым кому-то может понадобиться именованная константа, а не буква или значение, хранящееся в переменной:
Значение constexpr вычисляется во время выполнения компиляции, и если оно не может быть вычислено, то компилятор выдаст ошибку.
Многоликий const
Ключевое слово const — одно из самых многозначных в C++. Правильно использование const позволяет организовать множество проверок ещё на этапе компиляции и избежать многих ошибок из числа тех, которые бывает трудно найти при помощи отладчиков и/или анализа кода.
Первая половина заметки рассчитана скорее на начинающих (надеюсь мнемоническое правило поможет вам запомнить, где и для чего используется const), но, возможно, и опытные программисты смогут почерпнуть интересную информацию о перегрузке методов по const.
Константы и данные
Самый простой случай — константные данные. Возможно несколько вариантов записи:
Все они правильные и делают одно и тоже — создают переменную, значение которой изменить нельзя.
Константы и указатели
При использовании const с указателями, действие модификатора может распространяться либо на значение указателя, либо на данные на которые указывает указатель.
Работает (const относится к данным):
Тоже самое и тоже работает:
А вот это уже не работает:
Если бы операция присвоения изменяла бы не указатель, а данные:
то ситуация была бы диаметрально противоположной.
Существует мнемоническое правило, позволяющее легко запомнить, к чему относится const. Надо провести черту через «*», если const слева, то оно относится к значению данных; если справа — к значению указателя.
Ну и конечно, const можно написать дважды:
Константы и аргументы/результаты функций
C функциями слово const используется по тем же правилам, что при описании обычных данных.
Константы и методы (перегрузка)
А вот с методами есть одна тонкость.
Во-первых, для методов допустимо использование const, применительно к this. Синтаксис таков:
Кроме того, этот const позволяет перегружать методы. Таким образом, вы можете писать оптимизированные варианты методов для константных объектов.
То есть для константного объекта (с x=2) был вызван соответствующий метод.
Осталось только добавить, что если вы планируете использовать const-объекты, то вам надо обязательно реализовать const-методы. Если вы в этом случае не реализуете не-const-методы, то во всех случаях будут молча использоваться const-методы. Одним словом, const лучше использовать там, где это возможно.
И ещё… я собрался в отпуск… возможно, не смогу ответить на комментарии до понедельника-вторника. Не сочтите за невнимание 🙂