45940 (665245), страница 9

Файл №665245 45940 (Язык С) 9 страница45940 (665245) страница 92016-07-31СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 9)

Приспособьте идеи, использованные в PRINTD для рекурсив-

ного написания ITOA; т.е. Преобразуйте целое в строку с по-

мощью рекурсивной процедуры.

Упражнение 4-8.

Напишите рекурсивный вариант функции REVERSE(S), которая

располагает в обратном порядке строку S.

4.11. Препроцессор языка “C”.

В языке “с” предусмотрены определенные расширения языка

с помощью простого макропредпроцессора. одним из самых расп-

ространенных таких расширений, которое мы уже использовали,

является конструкция #DEFINE; другим расширением является

возможность включать во время компиляции содержимое других

файлов.

4.11.1. Включение файлов

Для облегчения работы с наборами конструкций #DEFINE и

описаний (среди прочих средств) в языке “с” предусмотрена

возможность включения файлов. Любая строка вида

#INCLUDE “FILENAME”

заменяется содержимым файла с именем FILENAME. (Кавычки обя-

зательны). Часто одна или две строки такого вида появляются

в начале каждого исходного файла, для того чтобы включить

общие конструкции #DEFINE и описания EXTERN для глобальных

переменных. Допускается вложенность конструкций #INCLUDE.

Конструкция #INCLUDE является предпочтительным способом

связи описаний в больших программах. Этот способ гарантиру-

ет, что все исходные файлы будут снабжены одинаковыми опре-

делениями и описаниями переменных, и, следовательно, исклю-

чает особенно неприятный сорт ошибок. Естественно, когда ка-

кой-TO включаемый файл изменяется, все зависящие от него

файлы должны быть перекомпилированы.

  • 96 -

4.11.2. Макроподстановка

Определение вида

#DEFINE TES 1

приводит к макроподстановке самого простого вида - замене

имени на строку символов. Имена в #DEFINE имеют ту же самую

форму, что и идентификаторы в “с”; заменяющий текст совер-

шенно произволен. Нормально заменяющим текстом является ос-

тальная часть строки; длинное определение можно продолжить,

поместив \ в конец продолжаемой строки. “Область действия”

имени, определенного в #DEFINE, простирается от точки опре-

деления до конца исходного файла. имена могут быть переопре-

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

ланные ранее. Внутри заключенных в кавычки строк подстановки

не производятся, так что если, например, YES - определенное

имя, то в PRINTF(“YES”) не будет сделано никакой подстанов-

ки.

Так как реализация #DEFINE является частью работы

маKропредпроцессора, а не собственно компилятора, имеется

очень мало грамматических ограничений на то, что может быть

определено. Так, например, любители алгола могут объявить

#DEFINE THEN

#DEFINE BEGIN {

#DEFINE END ;}

и затем написать

IF (I > 0) THEN

BEGIN

A = 1;

B = 2

END

Имеется также возможность определения макроса с аргумен-

тами, так что заменяющий текст будет зависеть от вида обра-

щения к макросу. Определим, например, макрос с именем MAX

следующим образом:

#DEFINE MAX(A, B) ((A) > (B) ? (A) : (B))

когда строка

X = MAX(P+Q, R+S);

будет заменена строкой

X = ((P+Q) > (R+S) ? (P+Q) : (R+S));

Такая возможность обеспечивает “функцию максимума”, которая

расширяется в последовательный код, а не в обращение к функ-

ции. При правильном обращении с аргументами такой макрос бу-

дет работать с любыми типами данных; здесь нет необходимости

в различных видах MAX для данных разных типов, как это было

бы с функциями.

  • 97 -

Конечно, если вы тщательно рассмотрите приведенное выше

расширение MAX, вы заметите определенные недостатки. Выраже-

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

побочные эффекты, вызванные, например, обращениями к функци-

ям или использованием операций увеличения. Нужно позаботить-

ся о правильном использовании круглых скобок, чтобы гаранти-

ровать сохранение требуемого порядка вычислений. (Рассмотри-

те макрос

#DEFINE SQUARE(X) X * X

при обращении к ней, как SQUARE(Z+1)). Здесь возникают даже

некоторые чисто лексические проблемы: между именем макро и

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

должно быть никаких пробелов.

Тем не менее аппарат макросов является весьма ценным.

Один практический пример дает описываемая в главе 7 стандар-

тная библиотека ввода-вывода, в которой GETCHAR и PUTCHAR

определены как макросы (очевидно PUTCHAR должна иметь аргу-

мент), что позволяет избежать затрат на обращение к функции

при обработке каждого символа.

Другие возможности макропроцессора описаны в приложении

А.

Упражнение 4-9.

Определите макрос SWAP(X, Y), который обменивает значе-

ниями два своих аргумента типа INT. (В этом случае поможет

блочная структура).

  • 98 -

5.Указатели и массивы

Указатель - это переменная, содержащая адрес другой пе-

ременной. указатели очень широко используются в языке “C”.

Это происходит отчасти потому, что иногда они дают единст-

венную возможность выразить нужное действие, а отчасти пото-

му, что они обычно ведут к более компактным и эффективным

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

собами.

Указатели обычно смешивают в одну кучу с операторами

GOTO, характеризуя их как чудесный способ написания прог-

рамм, которые невозможно понять. Это безусловно спрAведливо,

если указатели используются беззаботно; очень просто ввести

указатели, которые указывают на что-то совершенно неожидан-

ное. Однако, при определенной дисциплине, использование ука-

зателей помогает достичь ясности и простоты. Именно этот ас-

пект мы попытаемся здесь проиллюстрировать.

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

Так как указатель содержит адрес объекта, это дает воз-

можность “косвенного” доступа к этому объекту через указа-

тель. Предположим, что х - переменная, например, типа INT, а

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

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

рх = &х;

присваивает адрес х переменной рх; говорят, что рх “ука-

зывает” на х. Операция & применима только к переменным и

элементам массива, конструкции вида &(х-1) и &3 являются не-

законными. Нельзя также получить адрес регистровой перемен-

ной.

Унарная операция * рассматривает свой операнд как адрес

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

содержимое. Следовательно, если Y тоже имеет тип INT, то

Y = *рх;

присваивает Y содержимое того, на что указывает рх. Так пос-

ледовательность

рх = &х;

Y = *рх;

присваивает Y то же самое значение, что и оператор

Y = X;

Переменные, участвующие во всем этом необходимо описать:

INT X, Y;

INT *PX;

  • 99 -

с описанием для X и Y мы уже неодонократно встречались.

Описание указателя

INT *PX;

является новым и должно рассматриваться как мнемоническое;

оно говорит, что комбинация *PX имеет тип INT. Это означает,

что если PX появляется в контексте *PX, то это эквивалентно

переменной типа INT. Фактически синтаксис описания перемен-

ной имитирует синтаксис выражений, в которых эта переменная

может появляться. Это замечание полезно во всех случаях,

связанных со сложными описаниями. Например,

DOUBLE ATOF(), *DP;

говорит, что ATOF() и *DP имеют в выражениях значения типа

DOUBLE.

Вы должны также заметить, что из этого описания следу-

ет, что указатель может указывать только на определенный вид

объектов.

Указатели могут входить в выражения. Например, если PX

указывает на целое X, то *PX может появляться в любом кон-

тексте, где может встретиться X. Так оператор

Y = *PX + 1

присваивает Y значение, на 1 большее значения X;

PRINTF(“%D\N”, *PX)

печатает текущее значение X;

D = SQRT((DOUBLE) *PX)

получает в D квадратный корень из X, причем до передачи фун-

кции SQRT значение X преобразуется к типу DOUBLE. (Смотри

главу 2).

В выражениях вида

Y = *PX + 1

унарные операции * и & связаны со своим операндом более

крепко, чем арифметические операции, так что такое выражение

берет то значение, на которое указывает PX, прибавляет 1 и

присваивает результат переменной Y. Мы вскоре вернемся к то-

му, что может означать выражение

Y = *(PX + 1)

Ссылки на указатели могут появляться и в левой части

присваиваний. Если PX указывает на X, то

*PX = 0

  • 100 -

полагает X равным нулю, а

*PX += 1

увеличивает его на единицу, как и выражение

(*PX)++

Круглые скобки в последнем примере необходимы; если их опус-

тить, то поскольку унарные операции, подобные * и ++, выпол-

няются справа налево, это выражение увеличит PX, а не ту пе-

ременную, на которую он указывает.

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

ними можно обращаться, как и с остальными переменными. Если

PY - другой указатель на переменную типа INT, то

PY = PX

копирует содержимое PX в PY, в результате чего PY указывает

на то же, что и PX.

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

Так как в “с” передача аргументов функциям осуществляет-

ся “по значению”, вызванная процедура не имеет непосредст-

венной возможности изменить переменную из вызывающей прог-

раммы. Что же делать, если вам действительно надо изменить

аргумент? например, программа сортировки захотела бы поме-

нять два нарушающих порядок элемента с помощью функции с

именем SWAP. Для этого недостаточно написать

SWAP(A, B);

определив функцию SWAP при этом следующим образом:

SWAP(X, Y) /* WRONG */

INT X, Y;

{

INT TEMP;

TEMP = X;

X = Y;

Y = TEMP;

}

из-за вызова по значению SWAP не может воздействовать на

агументы A и B в вызывающей функции.

К счастью, все же имеется возможность получить желаемый

эффект. Вызывающая программа передает указатели подлежащих

изменению значений:

SWAP(&A, &B);

  • 101 -

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

указателем на A. В самой SWAP аргументы описываются как ука-

затели и доступ к фактическим операндам осуществляется через

них.

SWAP(PX, PY) /* INTERCHANGE *PX AND *PY */

INT *PX, *PY;

{

INT TEMP;

TEMP = *PX;

*PX = *PY;

*PY = TEMP;

}

Указатели в качестве аргументов обычно используются в

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

(Можно сказать, что SWAP вOзвращает два значения, новые зна-

чения ее аргументов). В качестве примера рассмотрим функцию

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

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

значения, по одному целому за одно обращение. Функция GETINT

должна возвращать либо найденное значение, либо признак кон-

ца файла, если входные данные полностью исчерпаны. Эти зна-

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

значение ни использовалось для EOF, даже если это значение

вводимого целого.

Одно из решений, основывающееся на описываемой в главе 7

функции ввода SCANF, состоит в том, чтобы при выходе на ко-

нец файла GETINT возвращала EOF в качестве значения функции;

любое другое возвращенное значение говорит о нахождении нор-

мального целого. Численное же значение найденного целого

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

целого. Эта организация разделяет статус конца файла и чис-

ленные значения.

Следующий цикл заполняет массив целыми с помощью обраще-

ний к функции GETINT:

INT N, V, ARRAY[SIZE];

FOR (N = 0; N < SIZE && GETINT(&V) != EOF; N++)

ARRAY[N] = V;

В результате каждого обращения V становится равным следующе-

му целому значению, найденному во входных данных. Обратите

внимание, что в качестве аргумента GETINT необходимо указать

&V а не V. Использование просто V скорее всего приведет к

Характеристики

Тип файла
Документ
Размер
2,35 Mb
Материал
Тип материала
Учебное заведение
Неизвестно

Список файлов реферата

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6521
Авторов
на СтудИзбе
302
Средний доход
с одного платного файла
Обучение Подробнее