Ссылка в качестве возвращаемого значения
Возвращаемое функцией значение также может быть объявлено ссылкой. Это позволяет использовать функцию в левой части присваивания. Рассмотрите такой пример:
////////////////////////////////////////////////////////#include <stdio.h>#include <assert.h>const int arrSize = 8;int &refItem(int indx) // Возвращает ссылку на элемент iArray[indx]{ static int iArray[arrSize]; // Проверка диапазона: // Tests a condition and possibly aborts. assert is a macro that expands // to an if statement; if test evaluates to zero, the assert macro calls // the _assert function and aborts the program assert(indx >= 0 && indx< arrSize); return iArray[indx];}int main(){ for (int i =0; i<arrSize; i++) refItem(i) = 1 << i; // Присваивает значение элементу iArray[i]. for (int i=0; i<arrSize; i++) printf("iArray[%02d] = %4d\n”, i, refItem(i)); return 0;}Вывод:
iArray[00] = 1iArray[01] = 2iArray[02] = 4iArray[03] = 8iArray[04] = 16iArray[05] = 32iArray[06] = 64iArray[07] = 128В первом из операторов for функция refltem() вызывается в левой части присваивания. Во втором for она возвращает значение, которое передается функции printf (). Обратите внимание, что, во-первых, массив iArray[] объявлен как статический локальный в refltem(), благодаря чему непосредственное обращение к нему вне этой функции невозможно. Во-вторых, refltem() попутно проверяет допустимость переданного ей индекса.
Пример 2. Функция удвоения:
#include <stdio.h>void mul2(int a, int &b);int main(int argc, char* argv[]){ int a=2, b=3; printf("1. a=%d b=%d\n", a, b); //2 3 mul2(a, b); printf("3. a=%d b=%d\n", a, b); //2 6 getchar(); return 0;}void mul2(int a, int &b) { a*=2; b*=2; printf("2. a=%d b=%d\n", a, b); //4 6}Передача массивов
Т.к. имя переменной-массива определяет его адрес, то при передаче в функцию массива операцию взятия адреса применять не следует. Массив всегда передается по адресу, поэтому его изменение в функции приведет к изменению фактического параметра.
Размер массива неважен при объявлении параметра. Все три приведенные записи
void f(int*);void f(int[]);void f(int[10]);эквивалентны. Контроль за тем, не является ли аргумент массивом, не производится. При передаче массива в качестве параметра часто необходимо указывать его размер. Обычно для такого указания используют дополнительный параметр функции.
void f(int[10], int size);Другой способ сообщить функции размер массива-параметра — объявить параметр как ссылку. В этом случае размер становится частью типа, и компилятор может проверить аргумент в полной мере.
void f(int (&arr)[10]);Для передачи массива по значению можно его поместить в структуру, которая содержит единственное поле — сам массив.
#include <stdio.h>typedef struct { int a[1]; } S;void f(int a[]){ a[0]=2;}void f2(S x){ x.a[0]=2;}int main(int argc, char* argv[]){ int a[1]={1}; printf("%d\n", a[0]); f(a); printf("%d\n", a[0]); S t; t.a[0]=1; printf("%d\n", t.a[0]); f2(t); printf("%d\n", t.a[0]); getchar(); return 0;}Прототип
Если требуется вызвать функцию до ее определения в рассматриваемом файле, или определение функции находится в другом исходном файле, то вызов функции следует предварять объявлением этой функции. Объявление (прототип) функции имеет следующий формат:
[спецификатор-класса-памяти] [спецификатор-типа] имя-функции ([список-формальных-параметров]) [,список-имен-функций];
В отличие от определения функции, в прототипе за заголовком сразу же следует точка с запятой, а тело функции отсутствует. Если несколько разных функций возвращают значения одинакового типа и имеют одинаковые списки формальных параметров, то эти функции можно объявить в одном прототипе, указав имя одной из функций в качестве имени-функции, а все другие поместить в список-имен-функций, причем каждая функция должна сопровождаться списком формальных параметров. Правила использования остальных элементов формата такие же, как при определении функции. Имена формальных параметров при объявлении функции можно не указывать, а если они указаны, то их область действия распространяется только до конца объявления.
Прототип — это явное объявление функции, которое предшествует определению функции. Тип возвращаемого значения при объявлении функции должен соответствовать типу возвращаемого значения в определении функции.
Если прототип функции не задан, а встретился вызов функции, то строится неявный прототип из анализа формы вызова функции. Тип возвращаемого значения создаваемого прототипа int, а список типов и числа параметров функции формируется на основании типов и числа фактических параметров, используемых при данном вызове.
Таким образом, прототип функции необходимо задавать в следующих случаях:
1. Функция возвращает значение типа, отличного от int.
2. Требуется проинициализировать некоторый указатель на функцию до того, как эта функция будет определена.
Наличие в прототипе полного списка типов аргументов параметров позволяет выполнить проверку соответствия типов фактических параметров при вызове функции типам формальных параметров, и, если необходимо, выполнить соответствующие преобразования.
В прототипе можно указать, что число параметров функции переменно, или что функция не имеет параметров.
Если прототип задан с классом памяти static, то и определение функции должно иметь класс памяти static. Если спецификатор класса памяти не указан, то подразумевается класс памяти extern.
Вызов функции имеет следующий формат:
адресное-выражение ([список-выражений])
Поскольку синтаксически имя функции является адресом начала тела функции, в качестве обращения к функции может быть использовано адресное-выражение, имеющее значение адреса функции.
Список-выражений представляет собой список фактических параметров, передаваемых в функцию. Этот список может быть и пустым, но наличие круглых скобок обязательно.
Выполнение вызова функции происходит следующим образом:
1. Вычисляются выражения в списке выражений и подвергаются обычным арифметическим преобразованиям. Затем, если известен прототип функции, тип полученного фактического аргумента сравнивается с типом соответствующего формального параметра. Если они не совпадают, то либо производится преобразование типов, либо формируется сообщение об ошибке. Число выражений в списке выражений должно совпадать с числом формальных параметров, если только функция не имеет переменного числа параметров. В последнем случае проверке подлежат только обязательные параметры. Если в прототипе функции указано, что ей не требуются параметры, а при вызове они указаны, формируется сообщение об ошибке.
2. Происходит присваивание значений фактических параметров соответствующим формальным параметрам.
3. Управление передается на первый оператор функции.
4. Выполнение оператора return в теле функции возвращает управление и возможно, значение в вызывающую функцию. При отсутствии оператора return управление возвращается после выполнения последнего оператора тела функции, а возвращаемое значение не определено.
Пример: Сколько нужно купить карточек спортлото, чтобы гарантированно угадать все номера?
#include <stdio.h>double fakt(int);int main(int argc, char* argv[]){ int n=49, m=6; printf("Count tickets = %-10.0lf", fakt(n)/fakt(n-m)/fakt(m)); getchar(); return 0;}double fakt(int x){ double p=1; for (int i=1; i<=x; i++) p*=i; return p;}Перед определением функции может находиться директива inline. Например:
inline int abs( int obj ){ // возвращает абсолютное значение obj return( obj < 0 ? -obj : obj );}В этом случае компилятор подставляет в точку вызова тело функции.
Дата добавления: 2016-07-27; просмотров: 1551;