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

Язык С
Строк программы, исключая математическое обеспечение Является учебным введением в центральную часть языка “C” Hачинаем. Единственный способ освоить новый язык Оператор FOR Набор полезных программ Подсчет символов Подсчет слов Функции Аргументы - вызов по значению Область действия: внешние переменные Резюме Константы Описания Преобразование типов До 9 и буквы от а до F Операции и выражения присваивания Старшинство и порядок вычисления Операторы и блоки Переключатель Цикл DO - WHILE Оператор CONTINUE Основные сведения Функции, возвращающие нецелые значения Еще об аргументах функций Правила, определяющие область действия Статические переменные Блочная структура Рекурсия Указатели и адреса Указатели и массивы Адресная арифметика Указатели символов и функции Указатели - не целые До 12, а не от 0 до 11. Так как за экономию памяти у нас пока не награждают, такой способ проще, чем подгонка индек-сов Инициализация массивов указателей Указатели на функции Структуры Структуры и функции Указатели на структуры Мы продемонстрируем, как правильно выполнить эту задачу Поля Определение типа Обращение к стандартной библиотеке Форматный вывод - функция PRINTF Форматный ввод - функция SCANF Форматное преобразование в памяти Обработка ошибок - STDERR и EXIT Обращение к системе Низкоуровневый ввод/вывод - операторы READ и WRITE Произвольный доступ - SEEK и LSEEK Пример - распечатка справочников Пример - распределитель памяти Константы Синтаксическая нотация Преобразования Первичные выражения Унарные операции Аддитивные операции Операция присваивания Спецификаторы типа Описание структур и объединений Инициализация TYPEDEF Оператор SWITCH Внешнее определение функции Область действия внешних идентификаторов Неявные описания Явные преобразования указателей Анахронизмы Операторы
439386
знаков
0
таблиц
0
изображений

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


·     106 -

и, кроме того, в главе 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;

 )


·     107 -

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

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

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

ми являются 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

·     108 -

 

истинно, если 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 дает число просмотренных символов,


·     108 -

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 


Информация о работе «Язык С»
Раздел: Информатика, программирование
Количество знаков с пробелами: 439386
Количество таблиц: 0
Количество изображений: 0

Похожие работы

Скачать
48443
0
0

... основаниям. При этом философская абстракция языка оказывается неразрывно связана с основными темами и движениями философии в целом. Более конкретно, на ранние стадии традиционно рассматриваемого в рамках АФ анализа обыденного языка глубокое влияние оказала философия Дж. Э. Мура, особенно его учение о здравом смысле, согласно которому такие понятия, как «человек», «мир», «я», «внешний мир», « ...

Скачать
43709
0
0

... и других странах СНГ, а также облегчение доступа к русской и мировой культуре и науке. Таким образом, судя по данным наших исследований, востребованность русского языка осталась в республике достаточно высокой. Многие представители современной молдавской молодежи продолжают, как их отцы и деды, тянуться к русской культуре, научным и техническим достижениям России. Русский язык остается языком ...

Скачать
39778
0
1

... рисуночное словесно-слоговое письмо). Памятники среднеэламского периода (14—12 вв. до н.э.) выполнены аккадской клинописью. Памятники новоэламского периода относятся к 8—6 вв. до н.э. Был официальным языком в персидском государстве Ахеменидов в 6—4 вв. предполагается, что он, подвергшись влиянию древнеперсидского, сохранился до раннего средневековья. 7. Бурушаски язык Язык бурушаски ( ...

Скачать
64931
0
0

... /диалект), скифский, согдийский, среднеперсидский, таджикский, таджриши (язык/диалект), талышский, татский, хорезмийский, хотаносакский, шугнано-рушанская группа языков, ягнобский, язгулямский и др. Они относятся к индоиранской ветви индоевропейских языков. Области распространения: Иран, Афганистан, Таджикистан, некоторые районы Ирака, Турции, Пакистана, Индии, Грузии, Российской Федерации. Общее ...

0 комментариев


Наверх