АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Операции с указателями

Читайте также:
  1. Ultra Lift – молодое, подтянутое тело без операции
  2. Активные операции
  3. Активные операции коммерческих банков, их структура.
  4. Акушерские операции при АУТ и КУТ
  5. Арифметические операции с выделениями
  6. Арифметические операции с матрицами
  7. Арифметические операции, типы данных в Maple
  8. Аутсорсинг, как форма кооперации предприятий
  9. Банковские операции.
  10. Булевские вектора и операции для работы с ними
  11. В день операции
  12. Введение в оперативную хирургию. Учение об операции

С указателями можно выполнять следующие операции: разадресация, или кос­венное обращение к объекту (*), присваивание, сложение с константой, вычита­ние, инкремент (++), декремент (--), сравнение, приведение типов. При работе с указателями часто используется операция получения адреса (&).

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

char a; // переменная типа char

char * р = new char; /* выделение памяти под указатель и под

динамическую переменную типа char */

*р = 'Ю'; а = *р; // присваивание значения обеим переменные

Как видно из примера, конструкцию *имя_указателя можно использовать в левой части оператора присваивания, так как она является L-значением, то есть определяет адрес области памяти. Для простоты эту конструкцию можно считать именем переменной, на которую ссылается указатель. С ней допустимы все действия, определенные для величин соответствующего типа (если указатель инициализирован). На одну и ту же область памяти может ссылаться несколько указателей различного типа. Примененная к ним операция разадресации даст разные результаты. Например, программа

#inc1ude <stdio.h>

int main(){

unsigned long int A = 0Xcc77ffaa;

unsigned short int* pint = (unsigned short int*) &A;

unsigned char* pchar = (unsigned char *) &A;

printf("| %x | %x | %x |", A, *pint, *pchar);

return 0;

}

на IBM PC-совместимом компьютере выведет на экран строку[1]:

| cc77ffaa | ffaa | аа |

 

Значения указателей pint и pchar одинаковы, но разадресация pchar дает в резуль­тате один младший байт по этому адресу, a pint – два младших байта. В приведенном выше примере при инициализации указателей были использова­ны операции приведения типов. Синтаксис операции явного приведения типа прост: перед именем переменной в скобках указывается тип, к которому ее требу­ется преобразовать. При этом не гарантируется сохранение информации, поэто­му в общем случае явных преобразований типа следует избегать.

При смешивании в выражении указателей разных типов явное преобразование типов требуется для всех указателей, кроме void*. Указатель может неявно пре­образовываться в значение типа bool(например, в выражении условного опера­тора), при этом ненулевой указатель преобразуется в true, а нулевой в false.

Присваивание без явного приведения типов допускается в двух случаях:

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

· если тип указателей справа и слева от операции присваивания один и тот же.

Таким образом, неявное преобразование выполняется только к типу void*. Зна­чение 0 неявно преобразуется к указателю на любой тип. Присваивание указате­лей на объекты указателям на функции (и наоборот) недопустимо. Запрещено и присваивать значения указателям-константам, впрочем, как и константам любо­го типа (присваивать значения указателям на константу и переменным, на кото­рые ссылается указатель-константа, допускается).

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

Инкремент перемещает указатель к следующему элементу массива, декремент — к предыдущему. Фактически значение указателя изменяется на величину sizeof(тип). Если указатель на определенный тип увеличивается или уменьшает­ся на константу, его значение изменяется на величину этой константы, умножен­ную на размер объекта данного типа, например:

short * р = new short [5];

р++; // значение р увеличивается на 2

long * q = new long [5];

q++; // значение q увеличивается на 4

Разность двух указателей – это разность их значений, деленная на размер типа в байтах (в применении к массивам разность указателей, например, на третий и шестой элементы равна 3). Суммирование двух указателей не допускается. При записи выражений с указателями следует обращать внимание на приорите­ты операций. В качестве примера рассмотрим последовательность действий, за­данную в операторе

*р++ = 10;

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

*р = 10; р++;

Выражение (*р)++, напротив, инкрементирует значение, на которое ссылается указатель.

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

 

Ссылки

Ссылка представляет собой синоним имени, указанного при инициализации ссылки. Ссылку можно рассматривать как указатель, который всегда разымено­вывается. Формат объявления ссылки:

тип & имя;

где тип – это тип величины, на которую указывает ссылка, & – оператор ссылки, означающий, что следующее за ним имя является именем переменной ссылочного типа, например:

int kol;

int& pal = kol; // ссылка pal - альтернативное имя для kol

const char& CR = '\n'; // ссылка на константу

 

Запомните следующие правила.

· Переменная-ссылка должна явно инициализироваться при ее описании, кро­ме случаев, когда она является параметром функции, описана как extern или ссылается на поле данных класса.

· После инициализации ссылке не может быть присвоена другая переменная.

· Тип ссылки должен совпадать с типом величины, на которую она ссылается.

· Не разрешается определять указатели на ссылки, создавать массивы ссылок и ссылки на ссылки.

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

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


[1] Старые версии компилятора могут выдать в результате строку | ffaa | cc77 | ffaa


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



Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.004 сек.)