Ссылка в качестве возвращаемого значения


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

////////////////////////////////////////////////////////#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; просмотров: 1547;


Поиск по сайту:

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

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.009 сек.