Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_С++_последная.doc
Скачиваний:
40
Добавлен:
07.05.2019
Размер:
876.54 Кб
Скачать

5.1.4. Тело функции

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

5.1.5. Фактические параметры

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

void swap (int *a, int *b);

{

int t;

t=*a;

*a=*b;

}

void main()

{

int x=5, y=6;

swap (&x,&y);

}

В примере функция swap объявлена как функция с двумя аргументами типа указателей на int. Формальные параметры a и b объявлены так же, как указатели на целые величины. При вызове функции адрес x запоминается в a, и адрес y запоминается в b. Теперь два имени или "синонима" существуют для одной и той же ячейки памяти. Ссылки *a и *b в функции swap действуют точно так же, как x и y в main. Присваивание внутри функции swap изменяет содержимое x и y.

5.1.6. Рекурсивные вызовы

Любая функция в С++ может быть вызвана рекурсивно. Для этого функция вызывает саму себя. Компилятор С++ допускает любое число рекурсивных вызовов, однако реально оно ограничивается размером стековой памяти. При каждом вызове формальных параметров и локальных переменных захватывается новая память, так что их значения из предшествующих незавершенных вызовов не перезаписываются. Пример рекурсивного вызова:

void f1 (int n);

{

int x;

f1 (x);

}

5.1.7. Передача параметров

Передача параметров в функцию может осуществляться двумя способами: по ссылке и по значению. В отличие от других языков, например Visual Basic, в С++ по умолчанию происходит передача по значению. Это означает, что в функции создается локальная переменная, в которую копируется значение из внешней переменной. Следующий пример иллюстрирует формат передачи параметров:

void fun (int a)

{

a=10; // присваиваем локальной переменной

}

void main()

{

int x=20;

fun (x); // не изменяем значение x

}

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

void fun(int *a)

{

*a=10; // присваиваем переменной x новое значение

}

void main()

{

int x=20;

fun(&x); // изменяем значение x

}

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

void fun(int *a, int N)

{

for(int i=0; i<N; i++)

a[i]=i*i; // заполняем массив

}

void main()

{

int x[10];

fun(x,10);

}

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

Наиболее важные моменты работы с функциями:

- функция – это именованная последовательность операторов, выполняющая законченное действие. Функции нужны для упрощения структуры программы;

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

- для вызова функции надо указать ее имя и набор аргументов;

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

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

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

- при написании функции нужно предусмотреть все возможные ошибки и обеспечить пользователя функции средствами их диагностики;

- печать диагностических сообщений внутри функции нежелательна;

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

- массивы всегда передаются в функцию по адресу. Количество элементов в массиве должно передаваться отдельным параметром;

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

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