Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

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






Адресная арифметика





 

Если P является указателем, то каков бы ни был сорт

объекта, на который он указывает, операция P++ увеличивает P

так, что он указывает на следующий элемент набора этих

объектов, а операция P +=I увеличивает P так, чтобы он ука-

зывал на элемент, отстоящий на I элементов от текущего эле-

мента.эти и аналогичные конструкции представляют собой самые

простые и самые распространенные формы арифметики указателей

или адресной арифметики.

Язык "C" последователен и постоянен в своем подходе к

адресной арифметике; объединение в одно целое указателей,

массивов и адресной арифметики является одной из наиболее

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

соответствующих возможностей языка на примере элементарной

(но полезной, несмотря на свою простоту) программы распреде-

ления памяти. Имеются две функции: функция ALLOC(N) возвра-

щает в качестве своего значения указатель P, который указы-

вает на первую из N последовательных символьных позиций, ко-

торые могут быть использованы вызывающей функцию ALLOC прог-

раммой для хранения символов; функция FREE(P) освобождает

приобретенную таким образом память, так что ее в дальнейшем

можно снова использовать. программа является "элементарной",

потому что обращения к FREE должны производиться в порядке,

обратном тому, в котором производились обращения к ALLOC.

Таким образом, управляемая функциями ALLOC и FREE память яв-

ляется стеком или списком, в котором последний вводимый эле-

мент извлекается первым. Стандартная библиотека языка "C"

содержит аналогичные функции, не имеющие таких ограничений,

и, кроме того, в главе 8 мы приведем улучшенные варианты.

Между тем, однако, для многих приложений нужна только триви-

альная функция ALLOC для распределения небольших участков

памяти неизвестных заранее размеров в непредсказуемые момен-

ты времени.

Простейшая реализация состоит в том, чтобы функция раз-

давала отрезки большого символьного массива, которому мы

присвоили имя ALLOCBUF. Этот массив является собственностью

функций ALLOC и FREE. Так как они работают с указателями, а

не с индексами массива, никакой другой функции не нужно

знать имя этого массива. Он может быть описан как внешний

статический, т.е. Он будет локальным по отношению к исходно-

му файлу, содержащему ALLOC и FREE, и невидимым за его пре-

делами. При практической реализации этот массив может даже

не иметь имени; вместо этого он может быть получен в резуль-

тате запроса к операционной системе на указатель некоторого

неименованного блока памяти.

Другой необходимой информацией является то, какая часть

массива ALLOCBUF уже использована. Мы пользуемся указателем

первого свободного элемента, названным ALLOCP. Когда к функ-

ции ALLOC обращаются за выделением N символов, то она прове-

ряет, достаточно ли осталось для этого места в ALLOCBUF. Ес-

ли достаточно, то ALLOC возвращает текущее значение ALLOCP

(т.е. Начало свободного блока), затем увеличивает его на N,

с тем чтобы он указывал на следующую свободную область. Фун-

кция FREE(P) просто полагает ALLOCP равным P при условии,

что P указывает на позицию внутри ALLOCBUF.

 

DEFINE NULL 0 /* POINTER VALUE FOR ERROR REPORT */

DEFINE ALLOCSIZE 1000 /* SIZE OF AVAILABLE SPACE */

 

TATIC CHAR ALLOCBUF[ALLOCSIZE];/* STORAGE FOR ALLOC */

TATIC CHAR *ALLOCP = ALLOCBUF; /* NEXT FREE POSITION */

 

HAR *ALLOC(N) /* RETURN POINTER TO N CHARACTERS */

INT N;

(

IF (ALLOCP + N <= ALLOCBUF + ALLOCSIZE) {

ALLOCP += N;

RETURN(ALLOCP - N); /* OLD P */

} ELSE /* NOT ENOUGH ROOM */

RETURN(NULL);

)

 

REE(P) /* FREE STORAGE POINTED BY P */

HAR *P;

(

IF (P >= ALLOCBUF && P < ALLOCBUF + ALLOCSIZE)

ALLOCP = P;

)

 

Дадим некоторые пояснения. Вообще говоря, указатель мо-

жет быть инициализирован точно так же, как и любая другая

переменная, хотя обычно единственными осмысленными значения-

ми являются NULL (это обсуждается ниже) или выражение, вклю-

чающее адреса ранее определенных данных соответствующего ти-

па. Описание

 

STATIC CHAR *ALLOCP = ALLOCBUF;

 

определяет ALLOCP как указатель на символы и инициализирует

его так, чтобы он указывал на ALLOCBUF, т.е. На первую сво-

бодную позицию при начале работы программы. Так как имя мас-

сива является адресом его нулевого элемента, то это можно

было бы записать в виде

 

STATIC CHAR *ALLOCP = &ALLOCBUF[0];

 

используйте ту запись, которая вам кажется более естествен-

ной. С помощью проверки

 

IF (ALLOCP + N <= ALLOCBUF + ALLOCSIZE)

 

выясняется, осталось ли достаточно места, чтобы удовлетво-

рить запрос на N символов. Если достаточно, то новое значе-

ние ALLOCP не будет указывать дальше, чем на последнюю пози-

цию ALLOCBUF. Если запрос может быть удовлетворен, то ALLOC

возвращает обычный указатель (обратите внимание на описание

самой функции). Если же нет, то ALLOC должна вернуть некото-

рый признак, говорящий о том, что больше места не осталось.

В языке "C" гарантируется, что ни один правильный указатель

данных не может иметь значение нуль, так что возвращение ну-

ля может служить в качестве сигнала о ненормальном событии,

в данном случае об отсутствии места. Мы, однако, вместо нуля

пишем NULL, с тем чтобы более ясно показать, что это специ-

альное значение указателя. Вообще говоря, целые не могут ос-

мысленно присваиваться указателям, а нуль - это особый слу-

чай.

Проверки вида

 

IF (ALLOCP + N <= ALLOCBUF + ALOOCSIZE)

и

IF (P >= ALLOCBUF && P < ALLOCBUF + ALLOCSIZE)

 

демонстрируют несколько важных аспектов арифметики указате-

лей. Во-первых, при определенных условиях указатели можно

сравнивать. Если P и Q указывают на элементы одного и того

же массива, то такие отношения, как <, >= и т.д., работают

надлежащим образом. Например,

 

P < Q

 

 

истинно, если P указывает на более ранний элемент массива,

чем Q. Отношения == и!= тоже работают. Любой указатель мож-

но осмысленным образом сравнить на равенство или неравенство

с NULL. Но ни за что нельзя ручаться, если вы используете

сравнения при работе с указателями, указывающими на разные

массивы. Если вам повезет, то на всех машинах вы получите

очевидную бессмыслицу. Если же нет, то ваша программа будет

правильно работать на одной машине и давать непостижимые ре-

зультаты на другой.

Во-вторых, как мы уже видели, указатель и целое можно

складывать и вычитать. Конструкция

 

P + N

 

подразумевает N-ый объект за тем, на который P указывает в

настоящий момент. Это справедливо независимо от того, на ка-

кой вид объектов P должен указывать; компилятор сам масшта-

бирует N в соответствии с определяемым из описания P разме-

ром объектов, указываемых с помощью P. например, на PDP-11

масштабирующий множитель равен 1 для CHAR, 2 для INT и

SHORT, 4 для LONG и FLOAT и 8 для DOUBLE.

Вычитание указателей тоже возможно: если P и Q указывают

на элементы одного и того же массива, то P-Q - количество

элементов между P и Q. Этот факт можно использовать для на-

писания еще одного варианта функции

 

STRLEN:

STRLEN(S) /* RETURN LENGTH OF STRING S */

CHAR *S;

{

CHAR *P = S;

 

WHILE (*P!= '\0')

P++;

RETURN(P-S);

}

При описании указатель P в этой функции инициализирован

посредством строки S, в результате чего он указывает на пер-

вый символ строки. В цикле WHILE по очереди проверяется каж-

дый символ до тех пор, пока не появится символ конца строки

\0. Так как значение \0 равно нулю, а WHILE только выясняет,

имеет ли выражение в нем значение 0, то в данном случае яв-

ную проверку можно опустить. Такие циклы часто записывают в

виде

 

WHILE (*P)

P++;

 

Так как P указывает на символы, то оператор P++ передви-

гает P каждый раз так, чтобы он указывал на следующий сим-

вол. В результате P-S дает число просмотренных символов,

 

т.е. Длину строки. Арифметика указателей последовательна:

если бы мы имели дело с переменными типа FLOAT, которые за-

нимают больше памяти, чем переменные типа CHAR, и если бы P

был указателем на FLOAT, то оператор P++ передвинул бы P на

следующее FLOAT. таким образом, мы могли бы написать другой

вариант функции ALLOC, распределяющей память для FLOAT,

вместо CHAR, просто заменив всюду в ALLOC и FREE описатель

CHAR на FLOAT. Все действия с указателями автоматически учи-

тывают размер объектов, на которые они указывают, так что

больше ничего менять не надо.

За исключением упомянутых выше операций (сложение и вы-

читание указателя и целого, вычитание и сравнение двух ука-

зателей), вся остальная арифметика указателей является неза-

конной. Запрещено складывать два указателя, умножать, де-

лить, сдвигать или маскировать их, а также прибавлять к ним

переменные типа FLOAT или DOUBLE.

 

 

Date: 2015-09-17; view: 338; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.011 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию