4390

Указатели и ссылки в языке С++

Контрольная

Информатика, кибернетика и программирование

Указатели и ссылки в языке С++ Указатели Обычно программисту не нужно знать реальный адрес каждой переменной, поскольку компилятор способен сам позаботиться о таких подробностях. Но если необходимость в этой информации все же возникает, то пол...

Русский

2012-11-18

57.5 KB

13 чел.

Указатели и ссылки в языке С++

  1.  Указатели

Обычно программисту не нужно знать реальный адрес каждой переменной, поскольку компилятор способен сам позаботиться о таких подробностях. Но если необходимость в этой информации все же возникает, то получить ее можно с помощью оператора обращения к адресу: &. Например, если в программе используется переменная Var типа unsigned short, то набрав команду:

cout<<&Var;

мы получим результат: 0012FF7C – адрес этой переменной в шестнадцатеричном коде. На другом компьютере результат может получиться другим.

Каждая переменная имеет адрес. Даже не зная сам адрес (номер ячейки памяти), значение его можно сохранить в другой переменной. Такая переменная, хранящая адрес другого объекта, и называется указателем (pointer).

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

Предположим, что существует целочисленная переменная howOld. Чтобы объявить указатель на нее по имени pAge, применяется следующая форма записи:

int *pAge=0;

В результате будет получена переменная pAge, предназначенная для хранения адреса значения типа int. В этом примере переменная pAge инициализируется нулевым значением. Указатели, значения которых равны нулю, называются пустыми (null pointer). После объявления указателю обязательно нужно присвоить какое-либо значение. Если предназначенный для хранения в указателе адрес заранее не известен, ему следует присвоить нулевое значение. Неинициализированные указатели называются дикими (wild pointer). Они очень опасны. Не шутите с этим, всегда инициализируйте указатели!

Присвоить адрес переменной howOld указателю pAge можно следующим образом:

int howOld=50;

int *pAge=0;

pAge=&howOld;

 Две последние строки можно объединить в одну:

int howOld=50;

int *pAge=&howOld;

В указателях звездочка (*) используется двумя различными способами: при объявлении указателя и в операторе косвенного доступа. При объявлении указателя звездочка (*) является частью синтаксиса и располагается после указания типа объекта. Например:

// объявить указатель на тип int

int *pAge = 0;

При косвенном доступе звездочка означает, что речь идет о значении в памяти, находящемся по адресу в данной переменной, а не о самом адресе.

// разместить значение 5 по адресу, находящемуся в pAge

*pAge = 5;

Заметьте, что тот же символ (*) используется как оператор умножения. Что именно имел в виду программист, поставив звездочку, компилятор определяет, исходя из контекста.

Наиболее часто указатели применяются для манипулирования данными в динамически распределяемой памяти. Оперативная память компьютера состоит из следующих областей:

  •  область глобальных переменных;
  •  динамически распределяемая память;
  •  регистры;
  •  сегменты программного кода;
  •  стек.

Стек представляет собой память, организованную по принципу LIFO (“Last In, First Out” – «Последним вошел, первым вышел»). Локальные переменные размещаются в стеке. Код программы размещается в сегментах. Регистры используются для внутренних целей процессора, например, для контроля вершины стека и указателя команд. Остальная часть памяти составляет так называемую динамически распределяемую память, или heap (кучу).

Особенностью локальных переменных является то, что после выхода из функции, в которой они были объявлены, память, выделенная для их хранения, освобождается, а значения переменных уничтожаются. Глобальные переменные позволяют частично решить эту проблему ценой неограниченного доступа к ним из любой точки программы, что значительно усложняет восприятие текста программы. Использование динамической памяти полностью решает обе проблемы.

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

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

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

Для выделения участка в динамически распределяемой области памяти используется ключевой слово new. Например, чтобы создать в динамически распределяемой памяти переменную типа int, необходимо ввести команду:

int *pPointer = new int;

Теперь мы можем записать

  *pPointer=72;

что можно прочитать так: «Разместить число 72 в той области динамически распределяемой памяти, на которую указывает pPointer».

По завершении работы с выделенной областью памяти ее нужно освободить. Для этого применяется оператор delete, после которого следует имя указателя. Например:

delete pPointer;

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

Поэтому каждый раз, когда в программе используется оператор new, за ним должен следовать оператор delete. Наилучшим способом нажить себе неприятностей является переприсвоение указателя без предварительного освобождения участка памяти, на который он указывает. Это приводит к утечке памяти. Рассмотрим следующий фрагмент кода:

int *pPointer = new int;

*pPointer = 72;

pPointer = new int;

*pPointer = 84;

В первой строке объявляется указатель pPointer и выделяется память для хранения переменной типа int. В следующей строке в выделенную область записывается значение 72. Затем в третьей строке указателю присваивается адрес другой области памяти, в которую записывается число 84 (строка 4). Теперь исходный участок памяти, содержащий значение 72, оказывается недоступен, поскольку указателю на эту область было присвоено новое значение. В результате невозможно ни использовать, ни освободить зарезервированную память до завершения программы. Правильно этот фрагмент выглядел бы так:

int *pPointer = new int;

*pPointer = 72;

delete pPointer;

pPointer = new int;

*pPointer = 84;

  1.  Ссылки

Ссылка (reference) – это псевдоним; при создании она инициализируется именем другого объекта, адресата. С этого момента ссылка выступает в роли альтернативного имени адресата, и все, что делается со ссылкой, происходит и с объектом. Ссылки обладают почти теми же возможностями, что и указатели, но синтаксис их несколько проще.

При объявлении ссылки вначале указывается тип объекта адресата, за которым следуют оператор ссылки (&) и имя ссылки.

int &rSomeRef=someInt;

Это можно прочитать как «rSomeRef  является ссылкой на целочисленное значение, инициализированное адресом переменной someInt».

Оператор ссылки (&) выглядит так же, как и оператор возвращения адреса, который используется при работе с указателями. Но это не один и тот же оператор, хотя они очень похожи. Пробел перед оператором ссылки обязателен, а пробел между оператором ссылки и именем ссылки необязателен.

  1.  Передача аргументов функции по ссылке

Функции имеют два ограничения: аргументы передаются как значения и теряют связь с исходными данными, а возвращать функция может только одно значение. Передавая функции аргументы по ссылке, можно преодолеть оба ограничения. В языке С++ передача данных по ссылке осуществляется двумя способами: либо с помощью указателей, либо с помощью ссылок. Ниже приведены примеры реализации функции swap(), обменивающей значения двух переменных, с помощью указателей и с помощью ссылок.

Листинг 6.1. Реализация функции swap() для работы с указателями

void swap (int *px, int *py)

{

int temp;

temp = *px;

*px = *py;

 *py = temp;

}

Для вызова функции swap() из основной программы используется команда swap(&x, &y).

Листинг 6.2. Реализация функции swap() для работы со ссылками

void swap (int &rx, int &ry)

{

int temp;

temp = rx;

rx = ry;

ry = temp;

}

Для вызова функции swap() из основной программы используется команда swap(x, y).

Как можно видеть, при работе со ссылками функции swap() передаются именно значения x и y, а не их адреса. Таким образом, благодаря использованию ссылок функция приобретает новую возможность изменять исходные данные в вызывающей функции, хотя при этом сам вызов функции ничем не отличается от обычного.

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

  1.  Возвращение нескольких значений

Как уже говорилось, функции могут возвращать только одно значение. Если необходимо вернуть несколько, то решением этой проблемы является передача функции нескольких объектов по ссылкам. В этом случае можно обойтись без главного возвращаемого значения, которое (зачем же добру пропадать?) можно использовать для сообщений об ошибках.

Листинг 6.3. Возвращение из функций нескольких значений при помощи ссылок

#include <iostream.h>

enum ERR_CODE {SUCCESS, ERROR};

ERR_CODE Factor(int, int&, int&); //Объявление функции

int main() {

int number, squared, cubed;

ERR_CODE result;

cout << ”Enter a number (0 – 20); “;

cin >> number;

result = Factor (number, squared, cubed);

if (result == SUCCESS)

{

cout << “number: “ << number << endl;

cout << “squared: “ << squared << endl;

cout << “cubed: “ << cubed << endl;

}

else

cout << “Error encountered!!” << endl;

char res;

cin>>res;

}

// Реализация функции

ERR_CODE Factor(int n, int &rSquared, int &rCubed) {

if (n > 20)

return ERROR;

else

{

rSquared = n*n;

rCubed = n*n*n;

return SUCCESS;

}

}

В этой программе функция Factor() вначале объявляется, а затем реализуется. Такая структура типична для профессиональных программ. Объявление записано выше функции main(), а реализация – ниже ее. В объявлении не обязательно писать имена аргументов, нужно только указать их типы. Объявление функции заканчивается точкой с запятой (в отличие от заголовка реализации функции).


 

А также другие работы, которые могут Вас заинтересовать

35144. Создание и заполнение справочников 8.26 MB
  Выполнить действия: А Выбрать пункт меню Справочник щелчком левой кнопки мыши Б Выбрать команду Фирмы щелчком левой кнопки мыши если разрешен учет по нескольким фирмам В Нажать клавишу SHIFTENTER для ввода новой фирмы Астра Г Заполнить реквизиты фирмы 2. Выполнить действия: А Выбрать пункт меню Справочник щелчком левой кнопки мыши Б Выбрать команду Места хранения щелчком левой кнопки мыши В Нажать клавишу Insert для ввода нового элемента Г в пункте Тип выбрать Склад Д в пункте Вид склада выбрать Склад оптовый Е Можно ввести...
35145. Ввод начальных остатков 2.75 MB
  12 в пункте Сумма: ничего не вводим в пункте Содержание операции: ввести для чего предназначена данная операция и Enter 4 Переходим к заполнению табличной части: А введем остатки по уставному фонду для Кливер и Русь колонка Дт – это дебет счета. Из выпадающего меню выбираем счет 00 это специально придуманный счет используемый только для введения остатков в данной программе и ENTER ENTER колонка Кт – это кредит счета. Из выпадающего меню выбираем счет 40 Уставной фонд и ENTER ENTER колонка СубконтоКт – это объект...
35146. Учет поступления материальных ценностей 16.32 MB
  Д в пункте Поставщик Контрагент из выпадающего меню выбрать группу Поставщики а затем элемент Ротонда Е в пункте Примечание можно дать краткую характеристику о вводимой информации Ж в пункте Номер счета поставщика задать номер З перейдем к заполнению табличной части: в колонке ТМЦ справочник номенклатура выбрать группу Товары элемент Костюм женский в колонке Ед. выбрать шт в колонке Колво ввести 31 все остальные колонки заполнятся автоматические ввести также товары костюм мужской и пиджак мужской и ОК И в результате...
35147. Информационные системы. Общие сведения 10.58 MB
  К средствам извлечения информации относятся: штатные средства ручного ввода клавиатура мышь; средства автоматизированного ввода с твердых копий сканеры; специализированные средства ручного ввода дигитайзеры световые перья сенсорные экраны; средства ввода речевой информации; средства ввода данных с аппаратуры датчики измерительные устройства аппаратура связи. Это программное обеспечение может быть как достаточно простым и предполагать только передачу операционной системе данных от аппаратных компонентов так и сложным...
35148. редства удалённого выполнения заданий в Windows 38 KB
  Планировщик заданий Windows осуществляет настройку как для локального компьютера так и для удаленной системы. На удаленных системах эта возможность обеспечивается совместной работой нескольких служб и программ: Планировщик заданий это стандартная служба Windows управляющая планировщиком заданий. Создание заданий на локальном компьютере осуществляется через: ПускВсе программыСтандартныеНазначенные задания Создание заданий на удаленном компьютере осуществляется через: Сетевое окружениеОтобразить компьютеры рабочей группывыбираем...
35149. Средства удалённого доступа к сети в Windows 40 KB
  в ОС Windows XP имеются встроенные инструменты для организации таких подключений : Remote Desktop Удаленный рабочий стол Remote ssistnce Удаленный помощник. Remote ssistnce Remote ssistnce позволяет пригласить другого пользователя друга знакомого специалиста для оказания помощи. При этом приглашенный участник в отличие от использования Remote Desktop может наблюдать за действиями пользователя. При этом Remote ssistnt самостоятельно управляет настройками соединения подстраивая объем передаваемых данных под возможности канала...
35150. Виртуальные частные сети. Архитектура и протоколы 42.5 KB
  VPN англ. В зависимости от применяемых протоколов и назначения VPN может обеспечивать соединения трёх видов: узелузел узелсеть и сетьсеть. Уровни реализации Обычно VPN развёртывают на уровнях не выше сетевого так как применение криптографии на этих уровнях позволяет использовать в неизменном виде транспортные протоколы такие как TCP UDP. Пользователи Microsoft Windows обозначают термином VPN одну из реализаций виртуальной сети PPTP причём используемую зачастую не для создания частных сетей.
35151. Методы повышения надёжности хранения данных. Технология RAID 50.5 KB
  Технология RID Одна из причин ведущих к утрате информации аппаратные сбои и поломки. RID это акроним от Redundnt rry of Independent Disks. Этим набором устройств управляет специальный RIDконтроллер контроллер массива который инкапсулирует в себе функции размещения данных по массиву; а для всей остальной системы позволяет представлять весь массив как одно логическое устройство ввода вывода. В зависимости от уровня RID проводится или зеркалирование или распределение данных по дискам.
35152. Цели и задачи администрирования 25 KB
  чтобы предоставить пользователям ИС наилучшее возможности по эффективному использованию ресурсов ИС при объективных ограничениях. 3 квалифицируемая помощь пользователям. Здесь задача состоит в том чтобы реализовать в ИС выбранную стратегию ИБ на базе 1 или нескольких политик безопасности обеспечить использование ИС только санкционированным пользователям предусмотреть резервное копирование и восстановления отдельных ресурсов или всей ИС.