- •Лабораторная работа №2 Структуры. Указатели.
- •1. Программирование алгоритмов с использованием структур
- •Краткие теоретические сведения
- •Пример на использование структур
- •2. Указатели Теоретические сведения
- •Указатели и операции над адресами
- •Операции над указателями (адресная арифметика)
- •Указатели на указатели
- •Таким образом, указатели на указатели – это имена многомерных массивов.
- •Массивы указателей
- •Динамическое размещение данных
- •Пример использования структуры и указателя
- •Варианты индивидуальных заданий Задание 1.
- •Задание 2.
2. Указатели Теоретические сведения
Указатель -это переменная, содержащая адрес памяти, где расположены другие объекты (переменные, функции и т.п.).
Принцип объявления указателей следующий:
тип *имя, где * -- обозначает указатель на.
Первый шаг в применении указателя - присвоить ему значение адреса. Для этого надо иметь возможность получить адрес, по которому в памяти расположен какой-то другой объект. Унарный оператор & выдает адрес объекта, так что инструкция р=&с; присваивает адрес ячейки с переменной р (говорят, что р указывает на с или, что то же, р ссылается нас). Оператор & применяется только к объектам, расположенным в памяти. Его операндом не может быть ни выражение, ни константа.
Унарный оператор * есть оператор раскрытия ссылки (или, унарная операция взятия косвенного адреса, или операция разыменования - запоминать ВСЕ необязательно, но знать что это такое - необходимо). Примененный к указателю он выдает объект, на который данный указатель ссылается. Предположим, что х и у целые, а ip- указатель на іnt. Следующие несколько строк показывают, каким образом объявляются указатели и используются операторы & и *.
int x=1, y=22, z[10];
int *ip; // ip – указатель на int
ip=&x; // теперь ip указывает на х
y=*ip; // y теперь равен 1
*ip=0 // x теперь равен 0
ip=&z[0]; //ip теперь указывает на z[0]
В С++ существует тесная связь между указателями и массивами. Любой доступ к элементу массива, осуществляемый операцией индексирования, может быть выполнен при помощи указателя. По определению имя массива - это адрес его нулевого элемента.
Можно определять указатели на структуры:
имя_структуры *имя_указателя на структуру;
Доступ к элементам структуры обеспечивает оператор стрелка (->). Формат соответствующего выжения следующий:
имя_указателя->имя_элемента_структуры
Оператор стрелка, состоящий из знака минус (-) и знака больше (>), записанных без пробела, обеспечивает доступ к элементам структуры через указатель на объект.
Указатели и операции над адресами
Обращение к объектам любого типа как операндам операций в языке C может проводиться:
- по имени, как мы до сих пор делали;
- по указателю (косвенная адресация).
Указатель – это переменная, которая может содержать адрес некоторого объекта в памяти компьютера, например адрес другой переменной. И через указатель, установленный на переменную можно обращаться к участку оперативной памяти, отведенной компилятором под ее значения.
Указатель объявляется следующим образом:
тип *идентификатор;
Например: int *a, *d;
float *f;
Здесь объявлены указатели a, d, которые можно инициализировать адресами целочисленных переменных и указатель f, который можно инициализировать адресами вещественных переменных.
С указателями связаны две унарные операции: & и *. Операция & означает «взять адрес» операнда (т.е. установить указатель на операнд). Данная операция допустима только над переменными. Операция * имеет смысл: «значение, расположенное по указанному адресу» и работает следующим образом:
- Определяется местоположение в оперативной памяти переменной типа указатель.
- Извлекается информация из этого участка памяти и трактуется как адрес переменной с типом, указанным в объявлении указателя.
- Производится обращение к участку памяти по выделенному адресу для проведения некоторых действий.
Пример 1:
int x, /* переменная типа int */
*y; /* указатель на элемент данных типа int */
y=&x; /* y - адрес переменной x */
*y=1; /* косвенная адресация указателем поля x
/* “по указанному адресу записать 1”, т.е. x=1; */
Пример 2:
int i, j=8, k=5, *y;
y=&i;
*y=2; /* i=2 */
y=&j; /* переустановили указатель на переменную j */
*y+=i; /* j+=i , т.е. j=j+1 -> j=j+2=10 */
y=&k; /*переустановили указатель на переменную k */
k+=*y; /* k+=k, k=k+k = 10 */
(*y)++; /* k++, k=k+1 = 10+1 = 11 */
Говорят, что использование указателя означает отказ от именования (разыменование) адресуемого им объекта.
Отказ от именования объектов при наличии возможности доступа по указателю приближает язык С по гибкости отображения «объект-память» к языку ассемблера.
При вычислении адресов объектов следует учитывать, что идентификатор массива и функции именует переместимую адресную константу (термин ассемблера), или константу типа указатель (термин языка C). Такую константу можно присвоить переменной типа указатель, но нельзя подвергать преобразованиям:
int x[100], *y;
y=x; // присваивание константы переменной
...
x=y; // Ошибка: в левой части - указатель-константа
Указателю-переменной можно присвоить значение другого указателя либо выражения типа указатель с использованием, при необходимости операции приведения типа (приведение необязательно, если один из указателей имеет тип "void *").
int i, *x;
char *y;
x=&i; /* x -> поле объекта int */
y=(char *)x; /* y -> поле объекта char */
y=(char *)&i; /* y -> поле объекта char */
Рассмотрим фрагмент программы:
int a=5, *p, *p1, *p2;
p=&a; p2=p1=p;
++p1; p2+=2;
printf(“a=%d, p=%d, p=%p, p1=%p, p2=%p.\n”,a,p,p,p1,p2);
Результат выполнения:
a=5, *p=5, p=FFC8, p1=FFCC, p2=FFD0.
Конкретные значения адресов зависят от ряда причин: архитектура компьютера, тип и размер оперативной памяти и т.д.