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

Язык С
Учебное введение Оператор FOR Копирование файла Подсчет строк Массивы Аргументы - вызов по значению Область действия: внешние переменные Резюме Константы Арифметические операции Затем, если один из операндов имеет тип DOUBLE, то другой преобразуется в DOUBLE, и результат имеет тип DOUBLE Побитовые логические операции Условные выражения Поток управления Переключатель Цикл DO - WHILE Оператор GOTO и метки Функции, возвращающие нецелые значения Внешние переменные Правила, определяющие область действия Статические переменные Инициализация Препроцессор языка “C” Указатели и адреса Адресная арифметика Указатели символов и функции Многомерные массивы Инициализация массивов указателей Структуры Массивы сруктур Указатели на структуры Поиск в таблице Объединения Ввод и вывод Средства ввода/вывода не являются составной частью языка “с”, так что мы не выделяли их в нашем предыдущем изложении Форматный вывод - функция PRINTF Обычные символы (не %), которые предполагаются совпадающими со следующими отличными от символов пустых промежутков символами входного потока Форматное преобразование в памяти Низкоуровневый ввод/вывод - операторы READ и WRITE Произвольный доступ - SEEK и LSEEK Пример - распределитель памяти Лексические соглашения Имеется шесть классов лексем: идентификаторы, ключевые слова, константы, строки, операции и другие разделители Характеристики аппаратных средств Следующая ниже таблица суммирует некоторые свойства аппаратного оборудования, которые меняются от машины к машине Первичные выражения Первичные выражения, включающие ., ->, индексацию и обращения к функциям, группируются слева направо Унарные операции Выражение с унарными операциями группируется справо налево Операции равенства Выражение-равенства: выражение == выражение выражение != выражение Операция запятая Выражение-с-запятой: выражение , выражение Внешние определения данных Снова о типах В этом разделе обобщаются сведения об операциях, которые можно применять только к объектам определенных типов Анахронизмы Так как язык “C” является развивающимся языком, в старых программах можно встретить некоторые устаревшие конструкции
424070
знаков
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;

)

Дадим некоторые пояснения. Вообще говоря, указатель может быть инициализирован точно так же, как и любая другая переменная, хотя обычно единственными осмысленными значениями являются 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 != '') P++;

RETURN(P-S);

} При описании указатель P в этой функции инициализирован посредством строки S, в результате чего он указывает на первый символ строки. В цикле WHILE по очереди проверяется каждый символ до тех пор, пока не появится символ конца строки . Так как значение равно нулю, а 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.


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

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

Скачать
48443
0
0

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

Скачать
43709
0
0

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

Скачать
39778
0
1

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

Скачать
64931
0
0

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

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


Наверх