Страницы

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

суббота, 28 декабря 2019 г.

Присваивание символа const char *

#cpp #c


Добрый день, хочу расставить точки над «i» для себя.

    const char *v = "123d";
    const char *c = "123";  
    c[2] = '5'; // Так нельзя 
    c = v;
    c = "asdfas";


Вопрос в следующем. Почему, когда мы const char * присваиваем строку, он присваивает,
а символ — нет? Может, где-то для const char * перегружен оператор присваивания, и
он ему присваивает новый адрес? А при присваивании литерала мы пытаемся записать по
тому же адресу?
    


Ответы

Ответ 1



Вопрос в следующем. Почему, когда мы const char * присваиваем строку, он присваивает, а символ — нет? Нужно различать константный указатель и указатель на константу. 1) Указатель на константу: нельзя менять содержимое объекта, на который указывает указатель, но можно менять содержимое самого указателя (указатель — это переменная, содержащая адрес другой переменной). char array[] = "string"; const char * с = array; // Указатель на объект, который нельзя менять c[1] = 'a'; // Нельзя, т. к. меняется содержимое указываемого объекта с = "345"; // Можно, т. к. меняется значение самого указателя 2) Константный указатель: можно менять содержимое объекта, но нельзя менять значение самого указателя. Проще говоря, указатель нельзя переназначить на другой объект, но сам указатель поменять можно. char array[] = "string"; char * const с = array; c[1] = 'a'; // можно с = "345"; // нельзя 3) Константный указатель на константу: совокупность первых двух. const char * const с = "123";

Ответ 2



После присваивания const char *c = "123"; в c храниться некий адрес, по которому размещена строка "123". Компилятор обычно размещает ее в памяти, которая "read only" (записать то можно туда, просто операционная система знает, что это неправильно и пресекает попытки записи). Но так как использовать будет только для чтения, то все нормально. Строка c[2] = '5'; пытается записать в эту неизменяемую память. Память только для чтения. Почему так сделано? для оптимизаций и упрощения. Пусть в Вашей программе есть ещё десять мест, где есть константа "123". Компилятор не будет создавать 11 копий, а будет использовать один и тот же адрес. А теперь представьте, что вышеуказанное изменение разрешено:). Старые компиляторы этого не делали и часто наблюдались интересные спецэффекты, когда константы изменяли свое значение. Но компилятор может поступить и по другому. const char * test = "test111"; printf(test); в этом случае может даже выбросить переменную test, а ее значение вывести непосредственно. присваивание c = v; разрешено, так как не изменяются данные по указателю, а только он сам. А указатель не константный. Аналогично и с присваиванием c = "asdfas";.

Ответ 3



Учебник по программированию на С++ говорит, что: Официальный тип строковых литералов, таких как "Привет",- const char []. Строка "Привет" имеет тип const char [7]. Секундочку! Ведь в слове Привет шесть букв, а не семь! Не переживайте, ошибки здесь нет. Дополнительный элемент содержит завершающий пустой символ, ' \0' (значение 0), который сообщает компьютеру длину строки. В конце каждого строкового литерала есть скрытый пустой символ (\0), который позволяет алгоритмам определять длину строки и факт достижения конца строки. Длина строки нужна не всем алгоритмам, но большинству из них. Присвоить строковый литерал переменной типа char* можно следующим образом: char* х = "Привет"; Однако со значением, на которое указывает х, нельзя работать. Если оно не будет постоянным, возникнет ошибка, как в следующем примере: *х = 'Т'; Этот код вызывает ошибку, потому что нельзя изменять значение константы. Чтобы получить строку, которую можно изменять, следует присвоить строковый литерал строковому объекту или символьному массиву. Пример объявления символьного массива, элементы которого могут изменяться: char s[] = "Привет"; s[0] = 'Т'; С этим кодом все в порядке, а новым значением строки будет "Тривет". Многие из стандартных библиотечных функций С принимают в качестве одного из аргументов значение типа char*. Однако если строка хранится в виде указателя на символ, ее длина не может быть определена, как в случае строковых литералов, завершаемых пустым символом. В отсутствие пустого символа невозможно понять, где кончается строка.

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

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