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

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

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

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

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

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

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

 

Машинный адрес 0012FF48 0012FF49 0012FF4A 0012FF4B 0012FF54 0012FF55 0012FF56 0012FF57 0012FF63
байт байт байт байт байт байт байт байт байт
Значение в памяти 2.015*10-6 'G'
Имя summa date ch

 

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

 

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

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 "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

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;

 

system("pause");

return 0;

}

Пример 2.

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

#include "stdafx.h"

#include <iostream>

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[]){

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;

//присваивание указателю значения выражения

*sc = c+a-b;

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а = " << ca;

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

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

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

system("pause");

return 0;

}

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

Пример 3.

#include "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

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";}

system("pause");

return 0;

}

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

Ключевые термины

Адрес объекта –это адрес области оперативной памяти, по которому хранится объект в соответствии с особенностями представления типа.

Инициализация указателя– это определение значения указателя.

Косвенная адресация– этообращение к области памяти не напрямую, по адресу, а через объект, которому в памяти соответствует определенный участок.

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

Переименование типов– это задание нового имени для существующего типа.

Производные типы данных – это типы, полученные на основе более простых базовых типов.

Разыменование– это операция получения значения объекта, адрес которого хранится в указателе;

Составные производные типы – это типы, являющиеся производными от различных существующих или ранее объявленных типов.

Указатель – это именованный объект, предназначенный для хранения адреса области памяти.

Указатель на константу– это указатель на такой объект, значение которого нельзя изменить в процессе выполнения программы.

Указатель-константа– это указатель, значение которого нельзя изменить в процессе выполнения программы.

Указатель-константа на константу– это указатель, для которого невозможно изменение как самого указателя, так и значения адресуемого объекта.

 

Краткие итоги

1.В языке С++ производные типы данных классифицируют в зависимости от построения на производные и непосредственно производные.

2.Для экономии памяти и времени, затрачиваемого на обращение к данным, в программах используют указатели на объекты.

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

4.Указатель может быть константой или переменной, а также указывать на константу или переменную.

5.Указатель типа void указывает на область памяти любого размера. Разыменование такого указателя необходимо проводить с операцией приведения типов.

6.До первого использования в программе объявленный указатель необходимо проинициализировать.

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

8.Над указателями определены операции: разыменование, взятие адреса, декремент, инкремент, увеличение (уменьшение) на целую константу, разность, определение размера.

9.Над указателями определены операции сравнения.

 

Набор для практики

Вопросы

1. Почему указатель не может существовать как самостоятельный тип?

2. С какой целью в программе может быть использован указатель типа void?

3. Что будет являться результатом разыменования указателя типа void без приведения типов?

4. Как изменится значение указателя после применения к нему операции инкремента (декремента)?

5. Почему для указателей определены сложение и вычитание только с целыми константами?

6. В чем отличие указателя на константу от указателя-константы?

7. Два указателя разных типов указывают на одно и то же место в памяти. Сравните результаты операций разыменования и взятия адреса с такими указателям. Сравните значения указателей.

8. Если объект занимает в памяти несколько байтов, то какой адрес является значением указателя на этот объект?

9. Каким образом при разыменовании указателей становится известно, сколько байтов памяти доступно?

 

Упражнения

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

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

3.Задано натуральное число. Разместите в памяти последовательно все его цифры, используя указатели и операции над ними.

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

 

 

Литература

1. Керниган, Б. Язык программирования Си / Б. Керниган, Д. Ритчи. – М.: Вильямс, 2007. – 304 с.

2. Подбельский, В.В. Практикум по программированию на языке Си: учеб. пособие / В.В. Подбельский. – М.: Финансы и статистика, 2004. – 576 с.

3. Подбельский, В.В. Программирование на языке Си: учеб. пособие / В.В. Подбельский, С.С. Фомин. – М.: Финансы и статистика, 2004. – 600 с.

4. Подбельский, В.В. Язык Си++: учеб. пособие / В.В. Подбельский. – М.: Финансы и статистика, 2005. – 560 с.

5. Романов, Е.Л. Практикум по программированию на языке С++: учеб. пособие / Е.Л. Романов. – СПб: БХВ-Петербург, 2004. – 432 с.

6. С/С++. Структурное программирование: практикум / Т.А. Павловская, Ю.А. Щупак. – СПб: Питер, 2004. – 239 с.









Дата добавления: 2017-06-02; просмотров: 1063;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.042 сек.