Студопедия — Доступ к значению переменной, хранящейся по адресу, с использованием операции разыменования называется непрямым доступом или разыменованием указателя.
Студопедия Главная Случайная страница Обратная связь

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

Доступ к значению переменной, хранящейся по адресу, с использованием операции разыменования называется непрямым доступом или разыменованием указателя.

Указатель на void

Отметим одну особенность указателей. Адрес, который мы помещаем в указатель, должен быть одного с ним типа. Мы не можем присвоить указателю на int адрес переменной типа float.

float fx=98.6;

int ptr = &fx; //так нельзя, типы int * и float * несовместны

Однако есть одно исключение. Существует тип указателя, который может указывать на любой тип данных. Он называется указателем на тип void и определяется следующим образом:

void *ptr.

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

int ix;

float fx;

int *iptr;

float *fptr;

void *vptr;

iptr =&ix;

fptr = &fx;

vptr = &ix;

vptr = &fx;

Следующие строки недопустимы

iptr - &fx;

fptr = &ix;

 

Указатели-константы и указатели переменные

Можно ли записать *(аггау++), т.е использовать операцию увеличения вместо прибавления шага j к имени array? Нет, так писать нельзя, поскольку нельзя изменять константы. Выражение array является адресом в памяти, где размещен наш массив, поэтому array - это указатель

константы. Мы не можем сказать аггау++, так же как не можем сказать 7++. Мы не можем увеличивать адрес, но имеем возможность увеличить указатель, который содержит этот адрес.
int main()

{

int array[5]={3 1,54,77,52,93};

intj;

int *prt;

prt = array;

for(j=0; j<5; j++) printf("%6d",*(prt++);

return 0;

}

Здесь мы определили указатель на int и затем присвоили ему значение адреса массива. После этого мы можем получить доступ к элементам массива, используя операцию разыменования *(prt++). Переменная pit имеет тот же адрес, что и array, поэтому доступ к первому элементу осуществляется как и раньше. Но prt - это уже переменная-указатель, то мы ее можем увеличивать. После этого она уже будет указывать на первый элемент массива array.

Передача простой переменной в функцию

Рассмотрим функцию void summ(int a, int b, int *us). 3-ий параметр объявлен в этой функции как указатель на int. Когда головная программа вызывает функцию summ, то она передает в качестве 3 аргумента адрес переменной summ(a, b,&s). Это не сама переменная, а ее адрес. Т.к. функция summ получает адрес переменной s, то она может применить к ней операцию разыменования *us = а+b. Т.к. us содержит адрес переменной s, то все действия, которые мы совершим с *us, мы в действительности совершим с s.

Передача массивов

Пусть мы хотим передать в функцию массив int A[10]. Прототип такой функции может выглядеть следующим образом void func(int[]). В этом случае мы обеспечиваем передачу массива по значению. Если мы хотим использовать аппарат указателей, то передача аргумента будет выглядеть как void func(int *).

Т.к. имя массива является его адресом, то нет нужды использовать при вызове функции операцию взятия адреса, т.е можно записать func(A).

Указатели и адреса

Начнем с того, что рассмотрим упрощенную схему организации памяти. Память типичной машины подставляет собой массив последовательно пронумерованных или проадресованных ячеек, с которыми можно работать по отдельности или связными кусками. Применительно к любой машине верны следующие утверждения: один байт может хранить значение типа char, двухбайтовые ячейки могут рассматриваться как целое типа short, а четырехбайтовые - как целые типа long. Указатель - это группа ячеек (как правило, две или четыре), в которых может храниться адрес. Так, если c имеет тип char, а p - указатель на c, то ситуация выглядит следующим образом:

Унарный оператор & выдает адрес объекта, так что инструкция

p = &c;

присваивает переменной p адрес ячейки c (говорят, что p указывает на c). Оператор & применяется только к объектам, расположенным в памяти: к переменным и элементам массивов. Его операндом не может быть ни выражение, ни константа, ни регистровая переменная.

Унарный оператор * есть оператор косвенного доступа. Примененный к указателю он выдает объект, на который данный указатель указывает. Предположим, что x и y имеют тип int, а ip – укаэатель на int. Следующие несколько строк придуманы специально для того, чтобы показать, каким образом объявляются указатели и как используются операторы & и *.

int х = 1, у = 2, z[10];

int *ip; ip - указатель на int

 

ip = &x; теперь ip указывает на x

y = *ip; y теперь равен 1

*ip = 0; x теперь равен 0

ip = &z[0]; ip теперь указывает на z[0]

 

Объявления x, y и z нам уже знакомы. Объявление указателя ip

int *ip;

мы стремились сделать мнемоничным - оно гласит: "выражение *ip имеет тип int ". Синтаксис объявления переменной "подстраивается" под синтаксис выражений, в которых эта переменная может встретиться. Указанный принцип применим и в объявлениях функций. Например, запись

double *dp, atof (char *);

означает, что выражения *dp и atof(s) имеют тип double, а аргумент функции atof есть указатель на char.

Вы, наверное, заметили, что указателю разрешено указывать только на объекты определенного типа. (Существует одно исключение: "указатель на void " может указывать на объекты любого типа, но к такому указателю нельзя применять оператор косвенного доступа)

Если ip указывает на x целочисленного типа, то *ip можно использовать в любом месте, где допустимо применение x; например,

*ip = *ip + 10;

увеличивает *ip на 10.

Унарные операторы * и & имеют более высокий приоритет, чем арифметические операторы, так что присваивание

y = *ip + 1;

берет то, на что указывает ip, и добавляет к нему 1, а результат присваивает переменной y. Аналогично

*ip += 1;

увеличивает на единицу то, на что указывает ip; те же действия выполняют

++*ip;

и

(*iр)++;

В последней записи скобки необходимы, поскольку если их не будет, увеличится значение самого указателя, а не то, на что он указывает. Это обусловлено тем, что унарные операторы * и ++ имеют одинаковый приоритет и порядок выполнения - справа налево.

И наконец, так как указатели сами являются переменными, в тексте они могут встречаться и без оператора косвенного доступа. Например, если iq есть другой указатель на int, то

iq = ip;

копирует содержимое ip в iq, чтобы ip и iq указывали на один и тот же объект.

Указатели и аргументы функций

Поскольку в Си функции в качестве своих аргументов получают значения параметров, нет прямой возможности, находясь в вызванной функции, изменить переменную вызывающей функции. В программе сортировки нам понадобилась функция swap, меняющая местами два неупорядоченных элемента. Однако недостаточно написать

swap(a, b);

где функция swap определена следующим образом:

void swap(int х, int у) /* НЕВЕРНО */

{

int temp;

temp = х;

x = y;

у = temp;

}

Поскольку swap получает лишь копии переменных a и b, она не может повлиять на переменные a и b той программы, которая к ней обратилась. Чтобы получить желаемый эффект, вызывающей программе надо передать указатели на те значения, которые должны быть изменены:

swap(&a, &b);

Так как оператор & получает адрес переменной, &a есть указатель на a. В самой же функции swap параметры должны быть объявлены как указатели, при этом доступ к значениям параметров будет осуществляться косвенно.

void swap(int *px, int *py) /* перестановка *px и *py */

{

int temp;

temp = *рх;

*рх = *py;

*ру = temp;

}

Графически это выглядит следующим образом: в вызывающей программе:

Аргументы-указатели позволяют функции осуществлять доступ к объектам вызвавшей ее программы и дают возможность изменить эти объекты.

 




<== предыдущая лекция | следующая лекция ==>
Прямой и обратный факторный анализ. | Завдання педагога полягає в тому, щоб підготувати дитину до вибору, спрямувати її душевні потяги на досягнення високих цілей.

Дата добавления: 2015-08-12; просмотров: 693. Нарушение авторских прав; Мы поможем в написании вашей работы!



Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...

Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

ОПРЕДЕЛЕНИЕ ЦЕНТРА ТЯЖЕСТИ ПЛОСКОЙ ФИГУРЫ Сила, с которой тело притягивается к Земле, называется силой тяжести...

СПИД: морально-этические проблемы Среди тысяч заболеваний совершенно особое, даже исключительное, место занимает ВИЧ-инфекция...

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

Кран машиниста усл. № 394 – назначение и устройство Кран машиниста условный номер 394 предназначен для управления тормозами поезда...

Приложение Г: Особенности заполнение справки формы ву-45   После выполнения полного опробования тормозов, а так же после сокращенного, если предварительно на станции было произведено полное опробование тормозов состава от стационарной установки с автоматической регистрацией параметров или без...

Измерение следующих дефектов: ползун, выщербина, неравномерный прокат, равномерный прокат, кольцевая выработка, откол обода колеса, тонкий гребень, протёртость средней части оси Величину проката определяют с помощью вертикального движка 2 сухаря 3 шаблона 1 по кругу катания...

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия