Язык программирования С является языком на основе функций (K&R 4.1). Функция представляет собой блок кода, определяющий, что должно быть сделано. Когда другой код вызывает эту функцию, выполняется ее код. Функция возвращает значение, которое подставляется как результат вызова функции.

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

int square(int i) {
return i * i;
}

Так выглядит вызов этой функции:

int i = square(3);

В силу ее определения приведенный код эквивалентен следующему:

int i - 9;

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

Проанализируем определение функции,

intO squareeieint i) {О return i * 1;<
}
  • Сначала указывается тип возвращаемого функцией значения; в данном случае это тип int.
  • Затем указывается имя функции; в данном случае это square.
  • После этого идут круглые скобки, в которых помещаются тип данных и имя всех значений, которые функция ожидает получить при вызове. В данном случае функция square ожидает получения одного значения типа int, которое мы называем 1. Имя i (вместе с ожидаемым типом данных) является параметром-, когда функция вызывается, его значение передается в функцию в качестве аргумента. Если функция ожидает получения более одного значения, несколько параметров в ее определении разделяются запятыми (при вызове функции передаваемые аргументы также разделяются запятыми).
  • Наконец, в фигурных скобках находятся инструкции, выполняемые при вызове функции.

Эти фигурные скобки образуют область видимости; объявленные в ней переменные являются локальными для данной функции. Имена, используемые для параметров в определении функции, также локальны по отношению к функции. Другими словами, переменная i в первой строке определения функции — то же самое, что и i во второй строке определения, но она не имеет ничего общего с любой i вне определения функции (например, если результат вызова функции присваивается переменной с именем i). Значение параметра i в определении функции присваивается из соответствующего аргумента, передаваемого при вызове функции; в предыдущем примере это 3, поэтому результатом функции является 9. Таким образом, вызов функции с аргументами является формой присваивания. Предположим, что функция определяется следующим образом:

int myfunction(int i, int j) ( // ...

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

int result = myfunction(3, 4);

Этот вызов функции присваивает значение 3 параметру i функции и значение 4 параметру j.

Когда встречается оператор return, сопутствующее ему значение передается обратно как результат вызова функции, и функция на этом завершается. Функция может не возвращать никакого значения; в таком случае оператор return не имеет сопутствующего значения, и тип данных, возвращаемых функцией, указывается в определении функции как void. Даже если функция возвращает значение, вызывающий код может его игнорировать. Например, вполне корректна запись

square (3) ;

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

9;

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

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

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

int square(int i) { return i * i;
)
int i = square(3);

Это вполне корректная программа, но только потому, что определение функции square предшествует ее вызову. Если мы хотим поместить определение функции square в другом месте, например, после ее вызова, то вызову должно предшествовать по крайней мере объявление функции square (пример 1.3). Объявление выглядит так же, как первая строка определения, но за которой следует точка с запятой, а не левая фигурная скобка.

 

Пример 1.3. Объявление, вызов и определение функции

int square(int i);
int i = square (3);
int square(int i) {
return i * i;
}

Имена параметров в объявлении не обязаны совпадать с таковыми в определении, но должны совпадать все типы (и, конечно, имя функции). Типы составляют сигнатуру функции. Другими словами, первая строка приведенного выше примера вполне может быть записана как

int square(int j);

Важно то, что и в объявлении, и в определении square представляет собой функцию, принимающую один параметр типа int и возвращающую значение типа int. (В современной программе Objective-C объявление функции обычно не требуется, даже если вызов функции предшествует ее объявлению; см. врезку “Функции и объявления методов в современной версии языка Objective-C”).

В Objective-C, когда вы отправляете объекту сообщение (глава 2), вы используете не вызов функции, а вызов метода (глава 3). Тем не менее вы будете также использовать массу вызовов

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

CGPoint CGPointMake(
CGFloat х,
CGFloat у
) ;

Несмотря на то что ее объявление располагается на нескольких строках и использует отступы, это настоящее объявление функции С, такое же, как объявление нашей простой функции square. Оно гласит, что CGPointMake представляет собой функцию С, которая принимает два параметра типа CGFloat и возвращает значение типа CGPoint. Так что теперь, надеюсь, вы знаете, что можно записать код с вызовом этой функции наподобие следующего:

CGPoint myPoint = CGPointMake(4.3, 7.1);

 

 

 

Добавить комментарий


Защитный код
Обновить