Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Производные типы. Тип указатель: указатели на объекты

Поиск

 

Цель работы: изучить тип указатель и соотношения между именами, адресами и значениями переменных, научиться использовать указатели в программных кодах на языке C++.

 

Теоретические сведения

В языке С++ разрешено использование наряду со стандартными типами производные типы, полученные на основе более простых базовых типов. Производные типы можно условно подразделить на две группы:

Непосредственно производные типы. Эти типы являются производными от некоторых существующих типов, реализуя типы указателей, ссылки, функции преобразования типов. В группу непосредственно производных типов входят:

· массивы;

· указатели;

· ссылки;

· перечисления.

Составные производные типы. В группу составных производных типов входят:

· классы;

· структуры;

· объединения.

 

Переименование типов

В некоторых программных кодах бывает удобно вводить новые обозначения имен отдельных используемых типов данных. Задавать новое имя типу можно с помощью ключевого слова typedef.

Синтаксис:

typedef Тип НовоеИмяТипа[Размерность];

Например:

typedef unsigned int UNIT;

typedef char Msg[100];

Такое имя можно затем использовать так же, как и стандартное имя типа:

UNIT a,b,c;//переменные типа unsigned int

Msg str[10];//массив из 10 строк по 100 символов

 

Рассмотрим тип указатель. Указатели являются специальными объектами в программах на С++. Они предназначены для хранения адресов памяти.

Пример: Когда компилятор обрабатывает оператор определения переменной, например, int i=10;, то в памяти выделяется участок памяти в соответствии с типом переменной (int=> 2 байта) и записывает в этот участок указанное значение. Все обращения к этой переменной компилятор заменит на адрес области памяти, в которой хранится эта переменная. Операция &a является операцией взятия адреса ее операнда.

 
 

 


Рис. Адресация в С++

 

Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями.

Указатель – именованный объект, предназначенный для хранения адреса области памяти (объекта, непоименованной области оперативной памяти либо точки входа в функцию).

Указатель не является самостоятельным типом, он всегда связан с каким-то другим типом. Указатели делятся на две категории:

· указатели на объекты;

· указатели на функции.

Эти категории указателей отличаются друг от друга свойствами и правилами манипулирования. Каждый указатель имеет соответствующий тип.

 

Указатели на объекты

В общем случае синтаксис определения указателя на объект:

Тип*Описатель

При определении указателя специфицируется имя указателя-переменной (в дальнейшем указатель) и тип объекта, на который он ссылается.

Тип задает тип объекта, адрес которого будет содержать эта переменная и может соответствовать базовому, пустому (свободному, родовому, то есть типу void), перечислению, структурному типу и типу объединения. Реально указатель на void ни на что не указывает, но обладает способностью указывать на все что угодно после его типизирования каким-либо объектом.

Описатель – это идентификатор, определяющий имя объявляемой переменой типа указатель или конструкция, которая организует непосредственно доступ к памяти. Описателю обязательно должна предшествовать звездочка (*).

Знак '*' является унарной операцией косвенной адресации, его операнд – указатель, а результат – адрес объекта, на который указывает операнд. Адресация является косвенной, так как обращение к области памяти осуществляется не напрямую по адресу (например, 1А2В), а через объект, которому в памяти соответствует определенный участок. Объем памяти, который выделяется для хранения данных, определяется типом данных и моделью памяти. Для приведенной на рисунке модели памяти адресом переменной типа char с именем ch является 1А2В, адресом переменной типа int с именем date является 1А2C, адресом переменной типа float с именем summa является 1А2E.

 

Машинный адрес 1А2В 1А2С 1А2D 1А2E 1А2F 1А30 1А31 1А32
байт байт байт байт байт байт байт байт
Значение в памяти 'G'   2.015*10-6  
Имя ch date summa  

 

Рис. Адресация типов в С++

 

Примеры определения указателей:

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 относится к указателю (т.е. находится между именем указателя и *), то он запрещает изменение значения указателя, а если он находится слева от типа (т.е. слева от *), то он запрещает изменение значения, на которое указывает указатель.

 

Способы инициализации указателя

1. Присваивание указателю адреса области памяти существующего объекта:

· с помощью операции получения адреса:

int a=5;

int *p=&a;

 

· с помощью проинициализированного указателя

int *r=p;

 

2. Присваивание указателю адреса области памяти в явном виде:

char *cp=(char*)0х В800 0000;

где 0х В800 0000 – шестнадцатеричная константа, (char*) – операция приведения типа.

 

3. Присваивание указателю пустого значения:

int *N=NULL; или int *N=0;

Спецификатор указателя при форматированном выводе

Если на экран необходимо вывести адрес, следует применять спецификатор %p.

%p – спецификатор указателя.

Этот спецификатор формата заставляет функцию printf() выводить на экран адрес, формат которого совместим с типом адресации, принятой в компьютере.

 

Операции с указателями

С указателями можно выполнять следующие операции:

· разыменование (*) – получение значения величины, адрес которой хранится в указателе;

· взятие адреса (&);

· присваивание;

· арифметические операции

§ сложение указателя только с константой,

§ вычитание: допускается разность указателей и разность указателя и константы,

§ инкремент (++) увеличивает значение указателя на величину sizeof(тип);

§ декремент (--) уменьшает значение указателя на величину sizeof(тип);

· сравнение;

· приведение типов.

Пример 1. Указатели различных типов указывают на одно и то же место в памяти. Однако при разыменовании получаются разные результаты.

// Выбор данных из памяти с помощью разных указателей

// Использование функций приведения типов

#include <iostream.h>

void main(){

unsigned long L=12345678;

char *cp=(char*)&L;

int *ip=(int*)&L;

long *lp=(long*)&L;

 

cout <<"\n&L = "<<&L;

cout <<"\nL = "<<L;

cout <<"\n*cp = "<<*cp;

cout <<"\n*ip = "<<*ip;

cout <<"\n*lp = "<<*lp;

}

Пример 2.

//Операции над указателями

#include <iostream.h>

void main(){

int a,c,b;

int *ca, *cb;

int *sa, *sb, *sc;

cout << "a = "; cin >> a;

cout << "b = "; cin >> b;

c=a+b;

 

sb=&b;//инициализация указателей через взятие адреса

sa=&a;

*sc=c;//инициализация указателя через обращение к переменной

ca=sa;//инициализация указателей через другой указатель

cb=sb;

*sa=12;//инициализация указателя через константу

 

cout << "\n*ca = " << *ca;

cout << "\n*sa = " << *sa;

cout << "\n*cb = " << *cb;

cout << "\n*sb = " << *sb;

cout << "\n*sc = " << *sc;

 

cout << "\nca = " << ca;

cout << "\ncb = " << cb;

cout << "\nsc = " << sc;

 

cout << "\na = " << a;

cout << "\nb = " << b;

cout << "\nc = " << c;

 

cout << "\n&a = " << &a;

cout << "\n&b = " << &b;

cout << "\n&c = " << &c;

 

cout << "\n*&a = " << *&a;

 

cout << "\n*cb-*ca = " << *cb-*ca;

cout << "\n*cb+*ca = " << *cb+*ca;

*cb=+2; //сложение с константой

cout << "\ncb = " << cb;

cb++; //инкремент

cout << "\ncb = " << cb;

ca--; //декремент

cout << "\ncа = " << cа;

/*разность указателей - разность их значений, деленная

на размер типа в байтах*/

cout << "\ncb-ca = " << cb-ca;

}

Указатели одного и того же типа можно сравнивать с помощью стандартных операций сравнения. При этом сравниваются значения указателей, а не значения величин, на которые данные указатели ссылаются.

Пример 3.

#include <iostream.h>

void main() {

int x=10;

int y=10;

int *xptr=&x;

int *yptr=&y;

 

//сравниваем указатели

if (xptr == yptr)

cout << "Указатели равны\n";

else

cout << "Указатели неравны\n";

 

//сравниваем значения, на которое указывает указатель

if (*xptr == *yptr) {

cout << "Значения равны\n";

} else {

cout << "Значения неравны\n";}

}

В приведенном примере результат первой операции сравнения будет ложным, а второй – истинным, поскольку переменные x и y имеют одно и то же значение.

Задания

1. Наберите код программы из Примера 2. Выполните компиляцию и запуск программы.

2. В программе определите и инициализируйте переменную типа double, указатель double * и указатель типа void *. Присвойте указателям адрес переменной. Напечатайте адрес переменной, значения указателей и значения, получаемые при разыменовании указателей. Чтобы продемонстрировать роли и последовательность выполнения унарных операций получения адреса & и разыменования *, выведите на печать значение выражения *&имя_переменной.

3. Определите и инициализируйте переменные разных типов (char, int, double) и один указатель типа void *. Последовательно присваивая указателю адреса переменных разных типов, выведите значения переменных с помощью разыменования указателя.

Домашние задания

1. Наберите коды программ из Примеров 1 и 3. Выполните компиляцию и запуск программ.

2. Определите и инициализируйте переменную типа double. Определите указатели char *, int *, double *, void *, инициализируйте их адресом переменной. Напечатайте значения указателей, их размеры и длины участков памяти, которые связаны с выражениями, разыменовывающими указатели.


Лабораторная работа 23



Поделиться:


Последнее изменение этой страницы: 2016-09-13; просмотров: 239; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 13.59.111.183 (0.01 с.)