Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь 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; просмотров: 360; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.135.208.236 (0.006 с.) |