Указатели. Viidad.. Понятие указателя Любой объект программы (переменная базового или производного типа) занимает в памяти определенную область. Местоположение.

Презентация:



Advertisements
Похожие презентации
Практическое занятие 6. Функции. Большинство языков программирования используют понятия функции и процедуры. C++ формально не поддерживает понятие процедуры,
Advertisements

УКАЗАТЕЛИ. Переменная - это именованная область памяти с заданным типом. [=значение]; int a; //Переменная типа integer с именем a int b=2;// Переменная.
Основы информатики Массивы. Указатели. Заикин Олег Сергеевич
Основы информатики Лекция. Функции Заикин Олег Сергеевич
Информационные технологии Классы памяти auto static extern register Автоматические переменные создаются при входе в функцию и уничтожаются при.
Лекция 6 Функции. Объявления и определения Объявление функции – указание имени функции, а также входных и выходных параметров Определение функции – указание.
Функции Функция – именованная последовательность описаний и операторов, выполняющая некоторое действие. Может иметь параметры и возвращать значение. Функция.
Лекция 2 С => C++ => C# Большие и маленькие буквы различаются (main, Main, MAIN, mAin – разные имена) После каждого оператора ставится точка с запятой.
Основы информатики Лекция. Массивы. Указатели. Заикин Олег Сергеевич
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
Лекция 6 Функции. Объявления и определения Объявление функции – указание имени функции, а также входных и выходных параметров Определение функции – указание.
МАССИВЫ 4 Определение 4 Описание 4 Обращение к элементам массива 4 Связь массивов с указателями 4 Примеры программ.
Лекция 5 Адресные типы. Указатели адрес (размещение в памяти) объекта Массивы последовательность однотипных данных Ссылки альтернативное имя объекта.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Лекция 8 Область видимости Время жизни. Область видимости Область видимости – характеристика именованного объекта Область видимости - часть текста программы,
Лекция 9 Функции. Массивы-параметры функции Передача массива в функцию Пример: void array_enter(int a[], int size) { int i; for (i = 0; i < size; i++)
Работа с файлами Сазонов Д.О. ПМиЭММ Часть 2. Тема занятия: Работа с файлами через потоки Для реализации файлового ввода/вывода, необходимо включить в.
ФГОБУ ВПО "СибГУТИ" Кафедра вычислительных систем УКАЗАТЕЛИ Преподаватель: Доцент Кафедры ВС, к.т.н. Поляков Артем Юрьевич © Кафедра вычислительных систем.
Тип, имя и значение переменной.. Переменные. В объектно-ориентированных языках программирования, и в частности в языке Visual Basic, переменные играют.
Занятие 4. Типы, определяемые пользователем, и указатели.
Транксрипт:

Указатели. Viidad.

Понятие указателя Любой объект программы (переменная базового или производного типа) занимает в памяти определенную область. Местоположение объекта в памяти определяется его адресом. При объявлении переменной для нее резервируется место в памяти, размер которого зависит от типа данной переменной, а для доступа к содержимому объекта служит его имя (идентификатор). Для того чтобы узнать адрес конкретной переменной, служит унарная операция взятия адреса. При этом перед именем переменной ставится знак амперсанда (&).

//Пример программы выведет на печать сначала значение переменной Varl и Var2, //а затем ее адрес: #include "stdafx.h" #include #define endl '\n' using namespace std; int main() { unsigned int Varl =40000; unsigned int Var2 =300; cout

2с с00 0x0068fdfc 0x0068fe00 Var2 Var1 300 = 12C = 9C40 16 Мощным средством разработчика программного обеспечения на С++ является возможность осуществления непосредственного доступа к памяти. Для этой цели предусматривается специальный тип переменных - указатели. Указатель (pointer) представляет собой переменную, значение которой является адресом ячейки памяти. Указатель может ссылаться на переменную (базового или производного типа) или функцию. Наибольшая эффективность применения указателей в разработке приложений достигается при использовании их с массивами и символьными строками.

Объявление указателя Объявление указателя имеет следующий синтаксис: * идентификатор; Символ 'звездочка' (*) сообщает компилятору, что объявленная переменная является указателем и, независимо от того, сколько памяти требуется отвести под сам объект, для указателя резервируется два или четыре байта в зависимости от используемой модели памяти. тип данных, на которые ссылается указатель с именем идентификатор

Поскольку указатель представляет собой ссылку на некоторую область памяти, ему может быть присвоен только адрес некоторой переменной (или функции), а не само ее значение. В случае некорректного присвоения компилятор выдаст соответствующее сообщение об ошибке. Рассмотрим пример объявления и инициализации указателя. char Symbol = 'Y'; //объявляется символьная переменная Symbol и //инициализируется значением 'Y' char *pSymbol = &Symbol; //определяется указатель на символьный тип данных //pSymbol, значение которого назначается равным //адресу переменной Symbol long Capital = 304L; //объявляется переменная Capital типа long long* pLong; //указатель на этот же тип pLong pLong = &Capital; //инициализация указателя адресом переменной //Capital

Разыменование указателей Указатели помогают осуществлять непосредственный доступ к памяти. Для того чтобы получить (прочитать) значение, записанное в некоторой области, на которую ссылается указатель, используют операцию косвенного обращения, или разыменования (*). При этом используется имя указателя со звездочкой перед ним: long double Num =10; long double Flag; long double *ptr = &Num; Flag = *ptr; cout

На практике довольно широко применяется так называемый пустой указатель (типа void), который может указывать на объект любого типа. Для получения доступа к объекту, на который ссылается указательvoid, его необходимо предварительно привести к тому же типу, что и тип самого объекта. Рассмотрим пример, иллюстрирующий использование пустого указателя. #include int main() { char Let = 'T'; int nNum = 9; void *ptr; ptr = &Let; *(char*)ptr = ' L '; ptr = bnNum; *(int*)ptr = 43; cout

Арифметика указателей К указателям (кроме указателей на переменные типа void) могут применяться арифметические операции. Для изменения пустого указателя он должен быть предварительно приведен к какому-либо типу (не void). Компилятор, зная тип указателя, вычисляет размер переменной этого же типа, после чего модифицирует адрес, содержащийся в указателе в соответствии с заданной арифметической операцией, но с учетом вычисленного для данного типа размера. Это означает, что если объявлен указатель типа double, занимающего в памяти 8 байт, операция, например, инкремента указателя увеличит значение адреса не на один, а на восемь байт: #include int main() { double Var; double* ptr = &Var; cout

Указатели можно вычитать друг из друга, тем самым определяя количество элементов (того же типа, на который указывают указатели), расположенных между ними. Этот прием бывает полезным при операциях с массивами и символьными строками, которые будут рассмотрены позже. Существует возможность использования при объявлении указателей ключевого слова const. При этом следует принимать во внимание, что применение данного спецификатора трактуется компилятором следующим образом: // Указатель на константу типа char // разыменованное значение неизменно const char* myKey; // Константный указатель типа int, // ВСЕГДА указывает на один и тот же адрес int* const Cell; Попытка модификации содержимого указателя на константу, как и применение любой арифметической операции к константному указателю, приведет к сообщению об ошибке.

Перечень допустимых арифметических операций над указателями: Наименование операции Пример Сравнение на равенствоp1== р2 Сравнение на неравенствоp1! = р2 Сравнение на меньшеp1< р2 Сравнение на меньше или равноp1 р2 Сравнение на больше или равно p1>= р2 Вычисление числа элементов между указа- телями p2 – p1 Вычисление указателя, отстоящего от задан- p1+ n ного на определенное в n число элементовp1- n

Применение к указателям оператора sizeof Как и к любой переменной или типу данных, к указателям можно применять операцию определения размера sizeof. Выше отмечалось, что размер указателя может принимать одно из двух значений: два или четыре байта, что позволяет указателю адресовать 2 (2*8) = 65 Кбайт или 2 (4*8) = 4 Гбайта памяти соответственно. На размер указателя (2 или 4 байта) влияет выбранная модель памяти и ряд других причин, которые будут рассмотрены в главах, посвященных моделям памяти и модификаторам. К указателям можно применять не только оператор sizeof, но и одноименную функцию, что и демонстрирует следующий пример.

#include "stdafx.h" #include int main() { char rea_lopp = '\n'; unsigned long u1Cone = ; bool IsTrue = false; unsigned long* pUL = &u1Cone; bool* pBool = &IsTrue; cout

Указатели на указатели Указатели могут сами ссылаться на другие указатели. При этом в ячейках памяти, на которые ссылается указатель, содержится не значение, а адрес какого-либо объекта. Сам объект может также являться указателем и т.д. На рисунке представлен вариант размещения в памяти указателя на указатель, который в свою очередь ссылается на однобайтный тип данных (например, char или bool). Здесь по Адресу+1 хранится значение некоторой переменной, на которую указывает обычный указатель, расположенный по Адресу+3 (хранит значение Адрес+1), на который в свою очередь ссылается указатель, расположенный по Адресу* 5 (содержит в качестве значения Адрес+3).

Синтаксис указателя на указатель выглядит следующим образом: // Объявление указателя на указатель int **pPtrInt; // ppSymbol - указатель на указатель, // который сам является указателем char ***ppSymbol; //При таком объявлении указатель может инициализироваться //адресом объекта: char* pSymb = &myChar; char** p_ptr = &pSyrnb; char*** ppptr = &p_ptr; Число символов 'звездочка' (*) при объявлении говорит о "порядке" указателя. Чтобы получить доступ к значению, такой указатель должен быть разыменован соответствующее количество раз (по числу символов '* ')

B приведенном ниже примере создается указатель второго порядка pPDX, содержащий адрес указателя pDX, который в свою очередь ссылается на переменную двойной точности. #include int main() { double dX = ; double *pDX = &dX; double **pPDX = &pDX; cout

В С++ указатели могут ссылаться на функции. Имя функции само по себе представляет константный указатель на эту функцию, то есть содержит адрес входа в нее. Однако можно задать свой собственный указатель на данную функцию: тип (*имя_указателя)(список_типа_аргументов) Например, bool (*MyFuncPtr)(char, long); объявляет указатель MyFuncPtr, ссылающийся на функцию, возвращающую логическое значение и принимающую в качестве параметров одну символьную и одну целую длинную переменную. Вызов функции через указатель осуществляется так, будто имя указателя является просто именем вызываемой функции. То есть после имени указателя следует список аргументов, ожидаемых функцией. Так, для приведенного выше указателя на функцию MyFuncPtr вызов может выглядеть, например, следующим образом: bool bVar; char Symbol = 'x'; long lNum = 0L; bVar = MyFuncPtr(Symbol, lNum); Указатели на функции

Пример использования указателя на функцию. Пусть задано какое-либо целое число, характеризующее месяц в году. Требуется определить, к какому сезону года относится данный месяц. #include bool Kevad(int x) {return (x>2 && x5 && x8 && x11 && x

Ссылки Ссылка - особый тип данных, являющийся скрытой формой указателя, который при использовании автоматически разыменовывается. Иными словами, он может использоваться просто как другое имя, или псевдоним объекта. При объявлении ссылки перед ее именем ставится знак амперсанда, а сама она должна быть тут же проинициализирована именем того объекта, на который ссылается: тип &имя_ссылки = имя_переменной; Тип объекта, на который указывается ссылка, может быть любым. Объявление неинициализированной ссылки вызовет сообщение компилятора об ошибке (кроме ситуации, когда ссылка объявляется как extern). Рассмотрим пример объявления ссылок: char Letter_A = 'А'; char &ref = Letter_A; Здесь объявляется и инициализируется символьная переменная Letter_A и ссылка на нее réf. Любое изменение значения ссылки повлечет за собой изменение того объекта, на который данная ссылка указывает: int i=0; int bref = i; ref += 10; // то же, что i += 10; После выполнения приведенного фрагмента значение обеих переменных i и ref будет равно 10.

Использование ссылок не связано с дополнительными затратами памяти. Следует отметить, что ссылки нельзя переназначать - инициализировав ссылку однажды адресом некоторой переменной, любое действие со ссылкой сказывается на самом объекте. Попытка переназначить имеющуюся ссылку какой-либо другой переменной приведет к присвоению оригиналу объекта значения второй переменной: char letA = 'А'; char urefA = letA; char B_Letter = 'В'; refA = B_Letter; //то есть letA = B_Letter Кроме того, следует учесть, что ссылаться можно только на сам объект. Нельзя объявить ссылку на тип объекта. Ниже приводится корректный вариант объявления. bool Flag = true; bool &ref = Flag; // а не bref = bool Еще одно ограничение, налагаемое на ссылки, заключается в том, что они не могут указывать на нулевой объект (принимающий значение NULL). Таким образом, если есть вероятность того, что объект в результате работы приложения станет нулевым, от ссылки следует отказаться в пользу применения указателя.

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

В С++ передача по ссылке может осуществляться двумя способами: используя непосредственно ссылки; с помощью указателей. Синтаксис передачи с использованием ссылок подразумевает применение в качестве аргумента ссылки на тип объекта. Например, функция double Glue(long& vari, int& var2); получает две ссылки на переменные типа long и int. При передаче в функцию параметра-ссылки компилятор автоматически передает в функцию адрес переменной, указанной в качестве аргумента (cтавить знак амперсанда перед аргументом в вызове функции не нужно). вызов функции с передачей параметров по ссылке Glue(vari, var2); прототип функции при передаче параметров через указатель: void SetNumber(int*, long*); функции могут возвращать не только значение некоторой переменной, но и указатель или ссылку на него. int Count(int); // возвращают указатель и ссылку соответственно &int Increase(); //на целочисленную переменную типа int.

Следует иметь в виду, что возвращение ссылки или указателя из функции может привести к проблемам, если переменная, на которую делается ссылка, вышла из области видимости. Например, int & func() { int х; return х; } В этом случае попытка возвратить ссылку на локальную переменную х приведет к ошибке, которая, к сожалению, выяснится только в ходе выполнения программы. Эффективность передачи адреса объекта вместо самой переменной ощутима и в скорости работы, особенно, если используются большие объекты, в частности массивы.

Если требуется в функцию передать довольно большой объект, однако его модификация не предусматривается, на практике используется передача константного указателя. Данный тип вызова предполагает использование ключевого слова const, например, функция const int* FName(int* const Number) принимает и возвращает указатель на константный объект типа int. Любая попытка модифицировать такой объект в пределах тела вызываемой функции вызовет сообщение компилятора об ошибке. Рассмотрим пример, иллюстрирующий использование константных указателей.

#include int* const call(int* const); int main() { int X = 13; //taisarvu deklareerimine ja initsialiseerimine int* рХ = &X; //viit pX sai X-muutujat aadressi call(pX); //funktsiooni väljakutsumine. Parameeter on viit pX, // mis teab X-muutujate aadress return 0; } int* const call(int* const x) {//kui funktsioon teab lokaal muutujat X aadressi, siis ta teab teda väärtust ka. // cout

Вместо приведенного выше синтаксиса константного указателя в качестве альтернативы при передаче параметров можно использовать константные ссылки, например: const int& FName(const int& Number) имеющие тот же смысл, что и константные указатели. #include const int& call(const int& x) { cout

Использование указателей и ссылок с ключевым словом const Некоторые конструкции языка С++ являются источником путаницы. Одной из таких конструкций является использование ключевого слова const с указателями и ссылками. // Объявление данных int number; const int count=0; // Указатель является константой int* const nl=&number; // Указатель указывает на константу (указываемое значение есть const) const int* n2=&count; // И указатель, и указываемое значение являются константами const int* const n3=&count; // Указатели на строки строка является константной const char* strl="text"; // Указатель на строку является константой char* const str2="text"; // Указатель и сама строка - константы const char* const str3="text"; /* Массивы указателей на символы */ // Символы являются константами const char* textl[]={"lnel",lnе2",lnеЗ"}; // Указатели являются константами char* const text2[]={"lnel",lnе2",lnеЗ"}; // Указатели и символы являются константами const char* const text3={"st1","st2","st3"};