Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информатика_и_Пр_Бизнес_лекции.doc
Скачиваний:
85
Добавлен:
10.05.2015
Размер:
1.21 Mб
Скачать

6. Указатели

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

Указатели используются для:

  • работы со строками и массивами;

  • работы с динамическими структурами данных, такими как очереди, списки, деревья, сети, графы;

  • передачи в функцию в качестве параметра адреса другой функции;

  • обмена данными между функциями в стиле языка С.

6.1. Объявление указателей

Синтаксис объявления переменной-указателя:

тип *имя_указателя;

где тип – это тип данных, на которые может ссылаться указатель.

Примеры объявлений указателей:

int *p1; //указатель на целое

float *p2, *р22; //указатели на вещественные данные

char *p3; // указатель на символ

char *p[15]; //массив из 15 указателей на символы

char (*p)[15] ;//указатель на массив из 15 символов

float **r; //указатель на указатель

Указателю при его объявлении можно присвоить начальное значение. Таким значением может быть адрес другой переменной или целое число 0. Указатель с нулевым значением не на что не указывает.

char c=’a’;

char *p3=&c; //& - операция получения адреса переменной

int *p4=0; //инициализация указателя нулем

int * const p=&x; //константный указатель, не может изменяться

const int * p1=&x; //указатель на константное целое значение

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

Присваивание

p1=p2

где р1 и p2 указатели одного типа.

Пример:

int x=2;

int y=1;

int *p1, *p2;

p1=&x; //p1 указывает на х

p2=p1; //р2 теперь также указывает на х

Операция косвенной адресации (разыменование)

где р указатель.

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

Пример:

int x=5;

int *p1; //объявление указателя

p1=&x; //р1 присваивается адрес х

cout<< *p1<<endl; //5 (обращение к х по адресу)

*p1=10; //изменение переменной х (обращение к х по адресу)

cout<<x; //10

Таким образом, к переменной можно обращаться по ее имени (прямо) и по ее адресу (косвенно).

Операции отношения

p1  p2

где p1 и p2 указатели одного типа, а  знак операции: ==, !=, <, >, <=, >=

Пример:

float x=0.4;

float *p1=&x;

float *p2;

p2=p1;

if (p1==p2) cout<< “equal”

else cout<<“no equal”;

Операция получения адреса

&p

где р указатель.

Пример:

int x=5;

int *p1=&x;

int **p2;

p2=&p1;

cout<<*p1<<’ ‘<<p1<<’ ‘<<*р2<<’ ‘<<**p2<<’ ‘<<p2<<endl;

//5 0063FE00 0063FE00 5 0063FDC

Операция сложения

p+k

где p – указатель, k – целое число.

Результатом операции р+k является адрес памяти, расположенной на k единиц дальше от начальных адресов памяти, чем память, адресуемая левым операндом. Длина единицы памяти в операции измеряется длиной базового типа указателя.

Пример:

int a[5]={10,20,30,40,50};

int *p1=&a[1];

p1=р1+3; //р1 увеличивается на 12 байтов

cout<<*p1; //50

char c[6]=”abcdef”;

char *p2=&c[1];

p2=р2+3; //р2 увеличивается на 3 байтa

cout<<*p2; //e

Операция вычитания

p-k

р1-р2

где p, p1 и p2 – указатели, p1 и p2 одного типа, k – целое число.

Результатом операции р-k является адрес памяти, расположенной на k единиц ближе к начальным адресам памяти, чем память, адресуемая левым операндом.

Пример:

int a[5]={10,20,30,40,50};

int *p1=&a[1];

p1=р1-1;

cout<<*p1; //10

Результатом операции р1-р2 является количество единиц памяти, между двумя адресами. Длина единицы памяти измеряется в операции длиной базового типа указателей.

Пример:

int a[5]={10,20,30,40,50};

int *p1=&a[1];

int *p2=&a[3];

cout<<p2-p1; //2

Операции инкремента и декремента

p++ и p- -

где p указатель.

Операции изменяют значение указателя на единицу памяти (равную емкости базового типа).

Пример:

int a[5]={10,20,30,40,50};

int *p1=&a[1];

int *p2=&a[3];

p1++;

p2--;

cout<<*p1<<’ ‘<<*p2; //30 30

Операция new

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

Операция new может использоваться следующими способами:

new тип

new тип (начальное значение)

new тип [количество элементов]

В первом способе операция выделяет участок динамической памяти, размер которого определяется емкостью указанного для операции типа. Во втором способе выделенная память инициализируется начальным значением. В третьем способе операция выделяет память под указанное количество элементов. Результатом операции является адрес выделенной памяти.

Примеры:

int *p;

p=new int; //выделение памяти под данное целого типа

*p=5;

int *p1;

p1=new int [10]; //выделение памяти под массив из 10 чисел

//Заполнение выделенной памяти

*p1=10;

*(p1+1)=20;

for (int i=2;i<10; i++)

*(p1+i)=(i-1)*10;

float p2;

p2=new float(0.5); //инициализация выделенной памяти

Память для динамических переменных выделяется из области памяти, которая называется динамической памятью или кучей (heap). Хотя эта область большая, но и она может исчерпаться. Поэтому программист должен заботиться о своевременном освобождении памяти, если необходимость в ней исчезает.

Если память выделить не удается, то создается исключительная ситуация bad_alloc, которая при отсутствии обработчика события завершает программу. Исключительная ситуация – это ошибка выполнения программы, которую можно перехватить, распознать и обработать.

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

Операция delete

delete p

delete [] p

где р указатель на динамическую память, выделенную операцией new.

Операция освобождает динамическую память (уничтожает динамические переменные). Если память выделялась под массив, то она должна освобождаться операцией delete []. При отсутствии [] будет освобождена память только от первого элемента массива, остальная выделенная под массив память останется помеченной как занятая. Кроме того адрес неосвобожденной памяти будет недоступен программе (поисходит «утечка памяти»).

Примеры:

int *p1;

p1=new int (5); //выделение и инициализация памяти под целое

//Здесь могут быть операторы, использующие р1

delete p1; //память возвращается в кучу для использования

p1=new int[3]; //выделение памяти под 3 целых числа

//здесь могут быть операторы, использующие р1

delete [] p1; //память возвращается в кучу для использования