Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сабуров С.В. - Язык программирования C и C++ - 2006

.pdf
Скачиваний:
312
Добавлен:
13.08.2013
Размер:
1.42 Mб
Скачать

Язык программирования Си

return (x*x);

void draw (x,y) int x,y;

.

.

.

return;

Функция main вызывает две функции: sq и draw. Функция sq возвращает значение x*x в main. Величина возврата присваивается переменной y. Функция draw объявляется как функция void и не возвращает значения. Попытка присвоить возвращаемое значение функции draw привело бы к ошибке.

Выражение <expression> оператора return заключено в скобки, как показано в примере. Язык не требует скобок.

Отсутствие оператора return

Если оператор return не появился в определении функции, то управление автоматически передается в вызывающую функцию после выполнения последнего оператора в вызванной функции. Значение возврата вызванной функции при этом не определено. Если значение возврата не требуется, то функция должна быть объявлена с типом возврата void.

Оператор switch

Синтаксис:

switch (<expression>) [<declaration>]

.

.

.

[case <constant expression>:]

.

.

.

[<statement>]

.

.

.

87

Язык программирования Си

[default:

<statement>]

[case <constant expression>:]

.

.

.

[<statement>]

.

.

.

Оператор switch передает управление одному из операторов <statement> своего тела. Оператор, получающий управление, — это тот оператор, чье case константное выражение

<constant expression> равно значению switch выражения

<expression> в круглых скобках.

Выполнение тела оператора начинается с выбранного оператора и продолжается до конца тела или до тех пор, пока очередной оператор <statement> передает управление за пределы тела.

Оператор default выполнится, если case константное выражение <constant expression> не равно значению switch выражения <expression>. Если default оператор опущен, а соответствующий case не найден, то выполняемый оператор в теле switch отсутствует. Switch выражение <expression> — это целая величина размера int или короче. Оно может быть также величиной типа enum. Если <expression> короче чем int, оно расширяется до int.

Каждое case константное выражение <constant expression> преобразуется к типу switch выражения. Значение каждого case константного выражения должно быть уникальным внутри тела оператора.

Case и default метки в теле оператора switch существенны только при начальной проверке, когда определяется стартовая точка для выполнения тела оператора. Все операторы появляющиеся между стартовым оператором и концом тела, выполняются, не обращая внимания на свои метки, если какой то из операторов не передает управления из тела оператора switch.

88

Язык программирования Си

В заголовке составного оператора, формирующего тело оператора switch, могут появиться объявления, но инициализаторы, включенные в объявления, не будут выполнены. Назначение оператора switch состоит в том, чтобы передать управление непосредственно на выполняемый оператор внутри тела, обойдя строки, которые содержат инициализацию.

Пример:

/***.....* example 1 *.....***/

switch (c) case 'A': capa++; case 'a': lettera++; default: total++;

Множественные метки

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

case 'a': case 'b': case 'c': case 'd': case 'e':

case 'f': hexcvt (c);

Хотя любой оператор внутри тела оператора switch может быть помечен, однако не требуется оператора, чтобы появилась метка. Операторы без меток могут быть смешаны с помеченными операторами. Следует помнить, однако, что если switch оператор передал управление одному из операторов своего тела, то все следующие за ним операторы в блоке выполняются, не обращая внимания на свои метки.

Оператор while

Синтаксис:

while (<expression>) <statement>

Тело оператора while выполняется нуль или более раз до тех пор, пока выражение <expression> станет ложным (равным нулю). Вначале вычисляется выражение <expression>. Если <expression>

89

Язык программирования Си

изначально ложно, то тело оператора while не выполняется и управление передается на следующий оператор программы. Если <expression> является истиной (не нуль), то выполняется тело оператора. Перед каждым следующим выполнением тела оператора <expression> перевычисляется. Повторение выполнения тела оператора происходит до тех пор, пока <expression> остается истинным. Оператор while может также завершиться при выполнении операторов break, goto, return внутри тела while.

Пример: while (i>=0)

string1 [i] = string2 [i]; i ;

В вышеприведенном примере копируются символы из string2 в string1. Если i больше или равно нулю, то string2[i] присваивается индексной переменной string1[i] и i декрементируется. Когда i становится меньше нуля, то выполнение оператора while завершается.

Функции

Функция — это независимая совокупность объявлений и операторов, обычно предназначенная для выполнения определенной задачи. Программы на Си состоят по крайней мере из одной функции main, но могут содержать и больше функций.

Определение функции специфицирует имя функции, ее формальные параметры, объявления и операторы, которые определяют ее действия. В определении функции может быть задан также тип возврата и ее класс памяти.

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

Чтобы обеспечить корректное обращение при других типах возвратов, необходимо объявить функцию перед ее вызовом.

90

Язык программирования Си

Вызов функции передает управление из вызывающей функции к вызванной. Действительные аргументы, если они есть, передаются по значению в вызванную функцию. При выполнении оператора return в вызванной функции управление и, возможно, значение возврата передаются в вызывающую функцию.

Определение функции

Определение функции специфицирует имя, формальные параметры и тело функции. Оно может также определять тип возврата и класс памяти функции. Синтаксис определения функции следующий:

[<sc specifier>][<type specifier>]<declarator> ([<parameter list>]) [<parameter declarations>]

<function body>

Спецификатор класса памяти <sc specifier> задает класс памяти функции, который может быть или static или extern. Спецификатор типа <type specifier> и декларатор <declaration>

специфицируют тип возврата и имя функции. Список параметров <parameter list> — это список (возможно пустой) формальных параметров, которые используются функцией. Объявления параметров <parameter declarations> задают типы формальных параметров. Тело функции <function body> — это составной оператор, содержащий объявления локальных переменных и операторы.

Класс памяти

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

Если спецификатор класса памяти опускается в определении функции, то подразумевается класс памяти extern. Спецификатор класса памяти extern может быть явно задан в определении функции, но этого не требуется.

Спецификатор класса памяти требуется при определении функции только в одном случае, когда функция объявляется

91

Язык программирования Си

где нибудь в другом месте в том же самом исходном файле с спецификатором класса памяти static. Спецификатор класса памяти static может быть также использован, когда определяемая функция предварительно объявлена в том же самом исходном файле без спецификатора класса памяти. Как правило, функция, объявленная без спецификатора класса памяти, подразумевает класс extern. Однако, если определение функции явно специфицирует класс static, то функции дается класс static.

Тип возврата

Тип возврата функции определяет размер и тип возвращаемого значения. Объявление типа имеет следующий синтаксис:

[<type specifier>] <declarator>

где спецификатор типа <type specifier> вместе с декларатором <declarator> определяет тип возврата и имя функции. Если <type specifier> не задан, то подразумевается, что тип возврата int. Спецификатор типа может специфицировать основной, структурный и совмещающий типы. Декларатор состоит из идентификатора функции, возможно модифицированного с целью объявления адресного типа. Функции не могут возвращать массивов или функций, но они могут возвращать указатели на любой тип, включая массивы и функции. Тип возврата, задаваемый в определении функции, должен соответствовать типам возвратов, заданных в объявлениях этой функции, сделанных где то в программе. Функции с типом возврата int могут не объявляться перед вызовом. Функции с другими типами возвратов не могут быть вызваны прежде, чем они будут определены или объявлены.

Тип значения возврата функции используется только тогда, когда функция возвращает значение, которое вырабатывается, если выполняется оператор return, содержащий выражение. Выражение вычисляется, преобразуется к типу возврата, если это необходимо, и возвращается в точку вызова. Если оператор return не выполняется или если выполняемый оператор return не содержит выражения, то значение возврата функции не определено. Если в этом случае вызывающая функция ожидает значение возврата, то поведение программы также не определено.

92

Язык программирования Си

Формальные параметры

Формальные параметры — это переменные, которые принимают значения, переданные функции от функционального вызова. Формальные параметры объявляются в списке параметров в начале описания функции. Список параметров определяет имена параметров и порядок, в котором они принимают значения при вызове функции.

Тело функции

Тело функции — это просто составной оператор. Составной оператор содержит операторы, которые определяют действия функции, и может также содержать объявления переменных, используемых в этих операторах. Все переменные, объявленные в теле функции, имеют тип памяти auto, если они не объявлены иначе. Когда вызывается функция, то создается память для локальных переменных и производится их инициализация (если она задана). Управление передается первому оператору составного оператора и начинается процесс выполнения, который продолжается до тех пор, пока не встретится оператор return или конец тела функции. Управление при этом возвращается в точку вызова.

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

Значение возврата не определено, если не выполнен оператор return или если в оператор return не было включено выражение.

Объявления функции

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

Функции могут быть объявлены неявно или в forward объявлениями. Тип возврата функции, объявленный или неявно или в forward объявлении, должен соответствовать типу возврата в определении функции. Неявное объявление имеет место всякий раз, когда функция вызывается без предварительного объявления или определения. Си компилятор неявно объявляет вызываемую функцию с типом возврата int. По умолчанию функция объявляется с классом памяти extern. Определение функции может переопределить класс памяти на

93

Язык программирования Си

static, обеспечив себе появление ниже объявлений в том же самом исходном файле. Forward объявление функции устанавливает ее атрибуты, позволяя вызывать объявленную функцию перед ее определением или из другого исходного файла.

Если спецификатор класса памяти static задается в forward объявлении, то функция имеет класс static. Поэтому определение функции должно быть также специфицировано классом памяти static.

Если задан спецификатор класса памяти extern или спецификатор опущен, то функция имеет класс памяти extern. Однако определение функции может переопределить класс памяти на static, обеспечив себе появление ниже объявлений в том же самом исходном файле

Forward объявление имеет важные различные применения. Они задают тип возврата для функций, которые возвращают любой тип значений, за исключением int. (Функции, которые возвращают значение int, могут также иметь forward объявления, но делать это не требуется).

Если функция с типом возврата не int вызывается перед ее определением или объявлением, то результат неопределен. Forward объявления могут быть использованы для задания типов аргументов, ожидаемых в функциональном вызове.

Список типов аргументов forward объявления задает тип и число предполагаемых аргументов. (Число аргументов может меняться). Список типов аргументов — это список имен типов, соответствующих списку выражений в функциональном вызове.

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

Вызовы функций

Вызов функции — это выражение, которое передает управление и фактические аргументы (если они есть) функции. Вызов функции имеет следующее синтаксическое представление:

<expression> ([<expression list>])

Выражение <expression> вычисляется как адрес функции. Список выражение <expression list>, в котором выражения следуют через запятую, представляет список фактических

94

Язык программирования Си

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

При выполнении вызова функции происходит замена формальных аргументов на фактические. Перед заменой каждый из фактических аргументов вычисляется. Первый фактический аргумент соответствует первому формальному аргументу, второй — второму и т.д.

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

Передача управления осуществляется на первый оператор функции. Выполнение оператора return в теле функции возвращает управление и, возможно, значение возврата в вызывающую функцию. Если оператор return не выполнен, то управление возвращается после выполнения последнего оператора тела функции. При этом величина возврата не определена.

Важно: Выражения в списке аргументов вызова функции могут выполняться в любом порядке, так что выражения с побочными эффектами могут дать непредсказуемые результаты. Компилятор только гарантирует, что все побочные эффекты будут вычислены перед передачей управления в вызываемую функцию.

Выражение перед скобками должно быть преобразовано к адресу функции. Это означает, что функция может быть вызвана через любое выражение типа указателя на функцию. Это позволяет вызывать функцию в той же самой манере, что и объявлять. Это необходимо при вызове функции через указатель. Например, предположим, что указатель на функцию объявлен как следующий:

int (* fpointer)(int,int);

Идентификатор fpointer указывает на функцию с двумя аргументами типа int и возвращающую значение типа int. Вызов функции в этом случае будет выглядеть следующим образом:

(* fpointer)(3,4);

Здесь используется операция разадресации (*), чтобы получить адрес функции, на которую ссылается указатель fpointer. Адрес функции затем используется для ее вызова.

95

Язык программирования Си

Фактические аргументы

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

Путь доступа из функции к значениям оригинальных переменных обеспечивают указатели. Т.к. указатель на переменную содержит адрес переменной, то функция может использовать этот адрес для доступа к значению переменной. Аргументы указатели обеспечивают доступ из функции к массивам и функциям, которые запрещено передавать как аргументы.

Тип каждого формального параметра также подвергается обычным арифметическим преобразованиям. Преобразованный тип каждого формального параметра определяет, каким образом интерпретируются аргументы в стеке. Если тип формального параметра не соответствует типу фактического параметра, то данные в стеке могут быть проинтерпретированы неверно.

Важно: Несоответствие типов формальных и фактических параметров может произвести серию ошибок, особенно когда несоответствие влечет за собой отличия в размерах. Нужно иметь в виду, что эти ошибки не выявляются, если не задан список типов аргументов в forward объявлении функции.

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

Чтобы вызвать функцию с переменным числом аргументов, в вызове функции просто задается любое число аргументов. В forward объявлении (если оно есть) переменное число аргументов специфицируется записью запятой с последующим многоточием (,...) в конце списка типов аргументов. Каждому имени типа, специфицированному в списке типов аргументов, соответствует один фактический аргумент в вызове функции. Если задано только многоточие (без имен типов), то это значит, что нет аргументов, которые обязательно требуются при вызове функции.

96

Соседние файлы в предмете Программирование на C++