Еще об аргументах функций

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

4.3. Еще об аргументах функций.

 

В главе 1 мы уже обсуждали тот факт , что аргументы фун-

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

свою временную копию каждого аргумента, а не его адрес. это

означает, что вызванная функция не может воздействовать на

исходный аргумент в вызывающей функции. Внутри функции каж-

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

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

ции обратились.


·     80 -

Если в качестве аргумента функции выступает имя массива,

то передается адрес начала этого массива; сами элементы не

копируются. Функция может изменять элементы массива, исполь-

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

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

зателей позволяет функциям воздействовать на отличные от

массивов переменные в вызывающих функциях.

Между прочим, несуществует полностью удовлетворительного

способа написания переносимой функции с переменным числом

аргументов. Дело в том, что нет переносимого способа, с по-

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

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

нии. Таким образом, вы, например, не можете написать дейст-

вительно переносимую функцию, которая будет вычислять макси-

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

функции MAX в фортране и PL/1.

Обычно со случаем переменного числа аргументов безопасно

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

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

ласуются. Самая распространенная в языке “C” функция с пере-

менным числом - PRINTF . Она получает из первого аргумента

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

гументов и их типы. Функция PRINTF работает совершенно неп-

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

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

пами, указанными в первом аргументе. Эта функция не является

переносимой и должна модифицироваться при использовании в

различных условиях.

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

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

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

(часто нуль) является признаком конца аргументов.

 

4.4. Внешние переменные.

 

Программа на языке “C” состоит из набора внешних объек-

тов, которые являются либо переменными, либо функциями. Тер-

мин “внешний” используется главным образом в противопостав-

ление термину “внутренний”, которым описываются аргументы и

автоматические переменные, определенные внурти функций.

Внешние переменные определены вне какой-либо функции и, та-

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

функции всегда являются внешними, потому что правила языка

“C” не разрешают определять одни функции внутри других. По

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

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

то же имя (даже из функций, скомпилированных независимо),

будут ссылками на одно и то же. В этом смысле внешние пере-

менные аналогичны переменным COмMON в фортране и EXTERNAL в

PL/1. Позднее мы покажем, как определить внешние переменные

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

но, а только в пределах одного исходного файла.


·     81 -

В силу своей глобальной доступности внешние переменные

предоставляют другую, отличную от аргументов и возвращаемых

значений, возможность для обмена данными между функциями.

Если имя внешней переменной каким-либо образом описано, то

любая функция имеет доступ к этой переменной, ссылаясь к ней

по этому имени.

В случаях, когда связь между функциями осуществляется с

помощью большого числа переменных, внешние переменные оказы-

ваются более удобными и эффективными, чем использование

длинных списков аргументов. Как, однако, отмечалось в главе

1, это соображение следует использовать с определенной осто-

рожностью, так как оно может плохо отразиться на структуре

программ и приводить к программам с большим числом связей по

данным между функциями.

Вторая причина использования внешних переменных связана

с инициализацией. В частности, внешние массивы могут быть

инициализированы а автоматические нет. Мы рассмотрим вопрос

об инициализации в конце этой главы.

Третья причина использования внешних переменных обуслов-

лена их областью действия и временем существования. Автома-

тические переменные являются внутренними по отношению к фун-

кциям; они возникают при входе в функцию и исчезают при вы-

ходе из нее. Внешние переменные, напротив, существуют посто-

янно. Они не появляютя и не исчезают, так что могут сохра-

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

другого. В силу этого, если две функции используют некоторые

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

то часто наиболее удобным оказывается хранить эти общие дан-

ные в виде внешних переменных, а не передавать их в функцию

и обратно с помощью аргументов.

Давайте продолжим обсуждение этого вопроса на большом

примере. Задача будет состоять в написании другой программы

для калькулятора, лучшей,чем предыдущая. Здесь допускаются

операции +,-,*,/ и знак = (для выдачи ответа).вместо инфикс-

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

польскую нотацию,поскольку ее несколько легче реализовать.в

обратной польской нотации знак следует за операндами; инфик-

сное выражение типа

 

(1-2)*(4+5)=

записывается в виде

12-45+*=

круглые скобки при этом не нужны


·     82 -

Реализация оказывается весьма простой.каждый операнд по-

мещается в стек; когда поступает знак операции,нужное число

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

меняется операция и результат направляется обратно в

стек.так в приведенном выше примере 1 и 2 помещаются в стек

и затем заменяются их разностью, -1.после этого 4 и 5 вво-

дятся в стек и затем заменяются своей суммой,9.далее числа

·     1 и 9 заменяются в стеке на их произведение,равное -9.опе-рация = печатает верхний элемент стека, не удаляя его (так что промежуточные вычисления могут быть проверены).

Сами операции помещения чисел в стек и их извлечения

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

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

точно длинными. Поэтому лучше оформить их в виде отдельных

функций,чем повторять соответствующий текст повсюду в прог-

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

ввода следующей операции или операнда. Таким образом, струк-

тура программы имеет вид:

 

WHILE( поступает операция или операнд, а не конец

IF ( число )

поместить его в стек

еLSE IF ( операция )

вынуть операнды из стека

выполнить операцию

поместить результат в стек

ELSE

ошибка

Основной вопрос, который еще не был обсужден, заключает-

ся в том,где поместить стек, т. Е. Какие процедуры смогут

обращаться к нему непосредственно. Одна из таких возможнос-

тей состоит в помещении стека в MAIN и передачи самого стека

и текущей позиции в стеке функциям, работающим со стеком. Но

функции MAIN нет необходимости иметь дело с переменными, уп-

равляющими стеком; ей естественно рассуждать в терминах по-

мещения чисел в стек и извлечения их оттуда. В силу этого мы

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

переменными , доступными функциям PUSH (помещение в стек) и

POP (извлечение из стека), но не MAIN.

Перевод этой схемы в программу достаточно прост. Ведущая

программа является по существу большим переключателем по ти-

пу операции или операнду; это, по-видимому, более характер-

ное применеие переключателя, чем то, которое было продемонс-

трировано в главе 3.

#DEFINE MAXOP 20 /* MAX SIZE OF OPERAND, OPERАTOR *

#DEFINE NUMBER '0' /* SIGNAL THAT NUMBER FOUND */

#DEFINE TOOBIG '9' /* SIGNAL THAT STRING IS TOO BIG *


·     83 -

MAIN() /* REVERSE POLISH DESK CALCULATOR */

/(

INT TUPE;

CHAR S[MAXOP];

DOUBLE OP2,ATOF(),POP(),PUSH();

WHILE ((TUPE=GETOP(S,MAXOP)) !=EOF);

SWITCH(TUPE) /(

CASE NUMBER:

PUSH(ATOF(S));

BREAK;

CASE '+':

PUSH(POP()+POP());

BREAK;

CASE '*':

PUSH(POP()*POP());

BREAK;

CASE '-':

OP2=POP();

PUSH(POP()-OP2);

BREAK;

CASE '/':

OP2=POP();

IF (OP2 != 0.0)

PUSH(POP()/OP2);

ELSE

PRINTF(“ZERO DIVISOR POPPED\N”);

BREAK;

CASE '=':

PRINTF(“\T%F\N”,PUSH(POP()));

BREAK;

CASE 'C':

CLEAR();

BREAK;

CASE TOOBIG:

PRINTF(“%.20S ... IS TOO LONG\N”,S)

BREAK;

/)

/)

#DEFINE MAXVAL 100 /* MAXIMUM DEPTH OF VAL STACK */

·      
84 -

INT SP = 0; /* STACK POINTER */

DOUBLE VAL[MAXVAL]; /*VALUE STACK */

DOUBLE PUSH(F) /* PUSH F ONTO VALUE STACK */

DOUBLE F;

/(

IF (SP < MAXVAL)

RETURN(VAL[SP++] =F);

ELSE /(

PRINTF(“ERROR: STACK FULL\N”);

CLEAR();

RETURN(0);

/)

/)

 

DOUBLE POP() /* POP TOP VALUE FROM STEACK */

/(

IF (SP > 0)

RETURN(VAL[--SP]);

ELSE /(

PRINTF(“ERROR: STACK EMPTY\N”);

CLEAR();

RETURN(0);

/)

/)

 

CLEAR() /* CLEAR STACK */

/(

SP=0;

/)

 

Команда C очищает стек с помощью функции CLEAR, которая

также используется в случае ошибки функциями PUSH и POP. к

функции GETOP мы очень скоро вернемся.

Как уже говорилось в главе 1, переменная является внеш-

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

ции. Поэтому стек и указатель стека, которые должны исполь-

зоваться функциями PUSH, POP и CLEAR, определены вне этих

трех функций. Но сама функция MAIN не ссылается ни к стеку,

ни к указателю стека - их участие тщательно замаскировано. В

силу этого часть программы, соответствующая операции = , ис-

пользует конструкцию

PUSH(POP());

 

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

изменяя его.

Отметим также, что так как операции + и * коммутативны,

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

щественен, но в случае операций - и / необходимо различать

левый и правый операнды.


·     85 -

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

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

расширение возможностей калькулятора. Включите операцию де-

ления по модулю /%/ и унарный минус. Включите команду “сте-

реть”, которая удаляет верхний элемент стека. Введите коман-

ды для работы с переменными. /Это просто, если имена пере-

менных будут состоять из одной буквы из имеющихся двадцати

шести букв/.

 


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

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

Скачать
48443
0
0

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

Скачать
43709
0
0

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

Скачать
39778
0
1

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

Скачать
64931
0
0

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

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


Наверх