Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Понятие указателя. Адресная арифметикаСодержание книги
Поиск на нашем сайте
В языке С++ существует два способа доступа к переменной: обращение к переменной по имени и использование механизма указателей. Указатель-переменная (или просто указатель) – это переменная, предназначенная для хранения адреса в памяти. Указатель-константа – это значение адреса оперативной памяти. В языке С++ определены две специальные операции для доступа к переменным через указатели: операция & и операция *. Результатом операции & является адрес объекта, к которому операция применяется. Например, &var1 дает адрес, по которому var1 хранится в памяти (точнее, адрес первого байта var1). Операция * - это операция обращения к содержимому памяти по адресу, хранимому в переменной-указателе или равному указателю-константе. Признаком переменной-указателя для компилятора является наличие в описании переменной двух компонентов: типа объекта данных, для доступа к которому используется указатель (т.е. на который ссылается указатель); символа * перед именем переменной. В совокупности тип и * воспринимаются компилятором как особый тип данных – «указатель на что-либо». Таким образом, описание int var1, *ptr; приводит к появлению переменной var1 и указателя-переменной ptr. Переменная var1 будет занимать два байта памяти. Указатель ptr имеет тип int* т.е. тип «указатель на целое». Место, выделяемое под такой тип компилятором, зависит от модели памяти. Указатели при их описании могут, как и обычные переменные, получать начальное значение. Например: int var1, ptr1 = (int*)200, *ptr2 = &var1; Здесь описаны две переменные-указатели ptr1 и ptr2; ptr1 получает начальное значение 200, а ptr2 в качестве начального значения – адрес, по которому в памяти хранится var1. Операцию * можно выразить словами: «взять содержимое по адресу, равного значению указателя». Например, оператор присваивания *ptr = *ptr2 + 4; можно интерпретировать так: взять содержимое памяти по адресу, равному значению указателя ptr2, прибавить к этому содержимому 4, а результат поместить по адресу, равному значению указателя ptr1. Число байтов, извлекаемых из памяти и участвующих в операции, определяется компилятором исходя из типа, на который указывает указатель. Запись типа *234 = var1; будет ошибкой, т.к. в левой части оператора присваивания записывается адрес константы, а константа в С++ не имеет адреса в памяти. Существуют ограничения и на использование операции взятия адреса &: нельзя определить адрес константы, например некорректным является выражение var1 = &0xff00; 2) нельзя определить адрес значения, получаемого при выполнении арифметического выражения, включающего знаки +, -, /, * и т.п. Например, некорректным является выражение int var1, *ptr; ptr = &(var1*3); 3) нельзя определить адрес переменной, описанной как register. Например, будет ошибкой попытка определить адрес var1: unsigned register var1; unsigned int *ptr; ptr = &var1; Сам указатель-переменная тоже имеет адрес. Поэтому, например, корректным будет такой фрагмент: int var1, *ptr1, *ptr2 = &var1; ptr1 = (int*)&ptr2; Здесь описываются два указателя-переменные и ptr2 инициализируется значением адреса переменной var1. Затем ptr1 присваивается значение адреса, по которому в памяти располагается ptr2. Указатель типа void* называют часто родовым (generic). Ключевое слово void говорит об отсутствии данных о размере объекта в памяти. Но компилятору для корректной интерпретации ссылки на память через указатель нужна информация о числе байтов, участвующих в операции. Поэтому во всех случаях использования указателя, описанного как void*, необходимо выполнить операцию явного приведения типа указателя. Например: unsigned long block = 0xffeeddccL; void *ptr = █ char ch; unsigned two_bytes; long int four_bytes; ch = *(char*) ptr; /* ch = 0xcc; */ two_bytes = *(unsigned*) ptr; /* two_bytes = 0xddcc; */ four_bytes = *(long int*) ptr; /* four_bytes = 0xffeeddcc; */ В комментариях приведены значения переменных, полученных в результате присваивания. Напомним, что младший байт всегда располагается в памяти по меньшему адресу. Для указателей-переменных разрешены некоторые операции: присваивание; инкремент или декремент; сложение или вычитание; сравнение. Язык С++ разрешает операцию сравнения указателей одинакового типа. При выполнении присваивания значение указателя в правой части выражения пересылается в ячейку памяти, отведенную для указателя в левой части. Важной особенностью арифметических операций с указателями является то, что физическое увеличение или уменьшение его значения зависит от типа указателя, т.е. от размера того объекта, на который указатель ссылается. Если к указателю, описанному как type*ptr; прибавляется или отнимается константа N, значение ptr изменяется на N*sizeof(type). Разность двух указателей type*ptr1, *ptr2 – это разность их значений, поделенная на sizeof(type). В частности, арифметические операции над указателями типа char* (размер типа равен 1) выполняются как над обычными целыми числами с той лишь разницей, что значения, участвующие в операции, - это адреса в оперативной памяти. Однако для других типов указателей это не так. Например: #include <stdio.h> void main(void) { int near*ptr1 = (int*)100; int near*ptr2 = (int*)200; ptr1 ++; ptr2 -= 10; printf("ptr2 = %d, ptr1 = %d, ptr2 – ptr1 = %d\n", ptr2, ptr1, ptr2 – ptr1); } Так как указатель имеет тип int* (длина типа 2 байта), то «единица изменения» указателя и «единица измерения разности» равны двум байтам. Для других типов указателей такие же вычисления дают следующий результат: для long* и float* ptr2 = 160, ptr1 = 104, ptr2 – ptr1 = 14, для double* ptr2 = 120, ptr1 = 108, ptr2 – ptr1 = 1, для long double* ptr2 = 100, ptr1 = 110, ptr2 – ptr1 = -1. Такие правила арифметических операций с указателями вытекают из того, что указатель в Си неявно рассматривается как указатель на начало массива однотипных элементов. Продвижение указателя вперед или назад совпадают с увеличением или уменьшением индекса элемента.
|
||
|
Последнее изменение этой страницы: 2017-02-05; просмотров: 435; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.216.196 (0.007 с.) |