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(), а реализация – ниже ее. В объявлении не обязательно писать имена аргументов, нужно только указать их типы. Объявление функции заканчивается точкой с запятой (в отличие от заголовка реализации функции).


 

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

38361. Праця як основа розвитку суспільства і чинник виробництва 399.5 KB
  Кожен суб’єкт ринкового господарства одночасно є і суб’єктом трудових відносин тому від знання економічних законів функціонування ринку праці зайнятості організації оплати праці великою мірою залежить ефективність використання ресурсів праці а також успіх підприємця й рівень життя населення країни. Це обумовлює об’єктивну необхідність набуття ґрунтовних знань основних положень економіки праці майбутніми фахівцями всіх економічних спеціальностей. Вивчення та аналіз закономірностей організації й результатів функціонування ринків праці...
38362. Соціально - трудові відносини на ринку праці 2.08 MB
  Навчально – методичний комплекс з дисципліни Економіка праці та соціально трудові відносини. €œСоціально трудові відносини на ринку праціâ€ для самостійної роботи студентів 3 курсу всіх форм навчання всіх спеціальностей Укл. 95 ПЕРЕДМОВА У даному навчальнометодичному комплексі розглянуто другий розділ дисципліни “Економіка праці та соціальнотрудові відносини†[Розділ 1 дивись джерело 25] присвячений питанням...
38363. Організація праці, її ефективність та оплата в умовах ринкових відносин 1.09 MB
  Ключовими проблемами дисципліни ЕП і СТВ є вартісні аспекти відображення витрат праці на створення одиниці продукції, тому, праця як суспільне явище повинна бути доцільно, ефективно та економічно організованою. Це може бути досягнуто за рахунок наукової організації праці, яка пов’язана зі створенням оптимальних організаційних умов поєднання людей і техніки в процесі праці
38364. Фінанси. Курс лекцій 2.83 MB
  Фінансова система України. Проблеми розвитку фінансової системи України та шляхи її вдосконалення. Враховуючи також ланки окремих сфер фінансової системи сучасна фінансова система України має такий вигляд Рис.
38365. Логистика и ее сущность 506.5 KB
  Параметрами материального потока являются: номенклатура ассортимент и количество продукции; габаритные характеристики объем площадь линейные размеры; весовые характеристики общая масса вес брутто вес нетто; физикохимическис свойства; характеристики тары упаковки; условия транспортировки и хранения; стоимостные характеристики и др.Характеристика микро и макрологистики Микрологистика изучает способы и методы оптимизации движения поступающих на предприятия обрабатываемых там и выходящих потоков продукции и сопутствующих...
38366. Міжнародні перевезення 35.31 KB
  Поняття міжнародних перевезень Транспорт одна з найважливіших галузей суспільного виробництва що покликана задовольняти потреби населення та інших галузей суспільного виробництва в перевезеннях. З допомогою транспортних засобів суб'єкти господарювання надають два різновиди послуг: перевезення вантажу пасажирів та їхнього багажу а також транспортування нафти природного газу електроенергії тощо. Міжнародними вважаються перевезення вантажів і пасажирів між двома чи кількома державами. На залізничному транспорті у разі відсутності угоди...
38367. Податкове право і податкове законодавство України 703.5 KB
  Ця структура включає в себе самостійні базові інститути оподаткування інститут оподаткування фізичних осіб; інститут місцевих податків і зборів; інститут податкової відповідальності тощо. Таким чином податкове право: виступає як інститут предметний тобто присвячений строго певному предмету різновиду відносин що складаються з приводу встановлення сплати й стягнення податків і зборів їх зміни й скасування; регулює суспільні відносини щодо встановлення й справляння податкових платежів їх зміни й скасування; розподіл і використання...
38368. Политология как научная дисциплина 284.5 KB
  при правлении Наполеона в Париже была открыта студия полит. Был проведён первый конгресс учённых по проблемам изучения полит. Под эгидой ЮНЕСКО проходит первый международный коллоквиум по проблемам полит. Они пришли к выводу что ПЛ как наука изучает: историю полит.
38369. Политология и ее развитие 246 KB
  Основные этапы развития политологии исторически определенные периоды становления и развития знаний о политике политической власти государстве политическом человеке и других вопросах политической жизни общества. Аквинского о божественном происхождении государства и власти моральном характере правления и другие вопросы оказали заметное влияние на политологию. Марксистсколенинская концепция политики исходила из признания экономического базиса первоосновой политической надстройки классовости политики которую определяла как область...