Производные типы. Тип указатель: указатели на объекты
Цель лекции: изучить классификацию производных типов, тип указатель и соотношения между именами, адресами и значениями переменных, научиться использовать указатели в программных кодах на языке C++.
В языке С++ разрешено наряду со стандартными использование производных типов, полученных на основе более простых базовых типов. Производные типы можно условно подразделить на две группы:
Непосредственно производные типы. Эти типы являются производными от некоторых существующих типов, реализуя типы указателей, ссылки, функции преобразования типов. В группу непосредственно производных типов входят:
- массивы;
- указатели;
- ссылки;
- перечисления.
Составные производные типы. В группу составных производных типов входят типы, являющиеся производными от различных существующих или ранее объявленных типов:
- классы;
- структуры;
- объединения.
Переименование типов
В некоторых программных кодах бывает удобно вводить новые обозначения имен отдельных используемых типов данных. Задавать новое имя типу можно с помощью ключевого слова typedef.
typedef Тип НовоеИмяТипа[Размерность];
Например:
typedef unsigned int UNIT; typedef char Msg[100];
Такое имя можно затем использовать так же, как и стандартное имя типа:
UNIT a,b,c;//переменные типа unsigned int Msg str[10];//массив из 10 строк по 100 символов
Рассмотрим тип указатель. Указатели являются специальными объектами в программах на С++. Они предназначены для хранения адресов памяти.
Рассмотрим пример ( рис. 4.1). Когда компилятор обрабатывает оператор определения переменной, например, int a=10;, то в памяти выделяется участок памяти в соответствии с типом переменной и записывается в этот участок указанное значение (размер типа int не менее 2 байтов и зависит от реализации). Все обращения к переменной a компилятор заменит на адрес области памяти, в которой хранится эта переменная. Операция &a является операцией взятия адреса ее операнда.
Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями.
Указатель – именованный объект, предназначенный для хранения адреса области памяти (объекта, непоименованной области оперативной памяти либо точки входа в функцию).
Указатель не является самостоятельным типом, он всегда связан с каким-то другим типом. Указатели делятся на две категории:
- указатели на объекты;
- указатели на функции.
Эти категории указателей отличаются друг от друга свойствами и правилами манипулирования. Каждый указатель имеет соответствующий тип.
Указатели на объекты
В общем случае синтаксис определения указателя на объект:
Тип*Описатель;
При определении указателя специфицируется имя указателя-переменной (в дальнейшем указатель) и тип объекта, на который он ссылается.
Тип задает тип объекта, адрес которого будет содержать определяемая переменная и может соответствовать базовому, пустому (свободному, родовому, то есть типу void ), перечислению, структурному типу и типу объединения. Реально указатель на void ни на что не указывает, но обладает способностью указывать на область любого размера после его типизирования каким-либо объектом.
Описатель – это идентификатор, определяющий имя объявляемой переменной типа указатель или конструкция, которая организует непосредственно доступ к памяти. Описателю обязательно должна предшествовать звездочка (*).
Знак '*' является унарной операцией косвенной адресации, его операнд – указатель, а результат – адрес объекта, на который указывает операнд. Адресация является косвенной, так как обращение к области памяти осуществляется не напрямую по адресу (например, 1А2В), а через объект, которому в памяти соответствует определенный участок. Объем памяти, который выделяется для хранения данных, определяется типом данных и моделью памяти. Для приведенной на рисунке 2 модели памяти адресом переменной типа float с именем summa является 0012FF48, адресом переменной типа int с именем date является 0012FF54, адресом переменной типа char с именем ch является 0012FF63.
Примеры определения указателей:
int *P; /*указатель Р может содержать адрес объекта типа int*/ float *s; /*указатель s может содержать адрес объекта типа float*/
Синтаксис объявления указателя на объект базового типа:
Тип*ИмяУказателя;
где ИмяУказателя – идентификатор.
Например,
char *s; //переменная s – указатель на объект типа char double *x; /*переменная х – указатель на объект типа double, вещественного числа с плавающей точкой удвоенной точности*/ int *k, *ff; //k, ff – указатели на объекты целого типа int *p, y; /*р – указатель на объект типа int, y – целочисленная переменная и не является указателем*/ int x, *p; /*х – целочисленная переменная и не является указателем, р – указатель на объект типа int*/
Указатель может быть константой или переменной, а также указывать на константу или переменную.
Например:
int i;//целая переменная const int ci=1; //целая константа int *pi; //указатель на целую переменную const int *pci; //указатель на целую константу int *const cpi; //указатель-константа на целую переменную const int *const cpc; //указатель-константа на целую константу
При объявлении указателя его можно сразу проинициализировать (задать значение):
int *pi=&i; //указатель на целую переменную const int *pci=&ci; //указатель на целую константу int *const cpi=&i; //указатель-константа на целую переменную const int *const cpc=&ci; //указатель-константа на целую константу
Если модификатор const относится к указателю (т.е. находится между именем указателя и *), то он запрещает изменение значения указателя, а если он находится слева от типа (т.е. слева от *), то он запрещает изменение значения, на которое указывает указатель.