Опубликован: 25.08.2010 | Уровень: для всех | Доступ: свободно
Лекция 4:

Функции

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Аннотация: Описание и использование функций. Параметры функции. Функции стандартной библиотеки С. Директивы препроцессора. Создание программ, состоящих из нескольких модулей. Области действия имен. Именованные области
Ключевые слова: функция, значение, абстракция, избыточность, отладка, программа, определение, объявление функции, компилятор, возвращаемое значение, список, последовательность операторов, фигурные скобки, область видимости, external, static, элемент списка, 'inline', обращение к функции, расходы, директива, вызов функции, выражение, оператор присваивания, память, автоматические переменные, стек, локальная переменная, статическая переменная, глобальные переменные, передача данных, прототип функции, передача параметров, объявление переменной, параметр, тело функции, операция присваивания, преобразование типов, переменная, копирование, встроенные типы, ссылка, инициализация, имя переменной, тип переменной, swapping, структура данных, фактический параметр, разыменование, const, место, размерность, компиляция, размерность массива, матрица, освобождение памяти, подпрограмма, стандартная библиотека, макрос, include, заголовочный файл, компоновка, ввод/вывод, математическая функция, поиск, сортировка, дисплей, поток информации, открытый файл, текстовый режим, возврат каретки, перевод строки, обратное преобразование, стандартный ввод, стандартный вывод, конец файла, fread, текстовый файл, монитор, указание типа, массив символов, нуль-символ, CSTRING, strcpy, strncpy, strcmp, strncmp, strcat, strncat, подстрока, strstr, strchr, strrchr, strpbrk, длина строки, strlen, управляющий символ, math, ABS, FAB, округленное число, ceiling, floor, CoS, экспонента, EXP, остаток, разбиение, модуль, интерфейс, заголовки, модульность, препроцессор, класс памяти, пробельный символ, полный путь, включаемый файл, встроенная функция, define, символические константы, подстановка, #ifdef, область действия, действующий идентификатор, статический элемент, область определения, namespace, вложенный блок, внешняя переменная, переменная функции, CPP, STD

Объявление и определение функций

Презентацию к лекции Вы можете скачать здесь.

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

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

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

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

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

Объявление функции (прототип, заголовок, сигнатура) задает ее имя, тип возвращаемого значения и список передаваемых параметров.

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

[ класс ] тип имя ([ список_параметров ])[throw ( исключения )]{ тело функции }

Рассмотрим составные части определения.

  • С помощью необязательного модификатора класса можно явно задать область видимости функции, используя ключевые слова extern и static:
    • extern - глобальная видимость во всех модулях программы (по умолчанию);
    • static - видимость только в пределах модуля, в котором определена функция.
  • Тип возвращаемого функцией значения может быть любым, кроме массива и функции (но может быть указателем на массив или функцию). Если функция не должна возвращать значение, указывается тип void.
  • Список параметров определяет величины, которые требуется передать в функцию при ее вызове. Элементы списка параметров разделяются запятыми. Для каждого параметра, передаваемого в функцию, указывается его тип и имя (в объявлении имена можно опускать).

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

На имена параметров ограничений по соответствию не накладывается.

Функцию можно определить как встроенную с помощью модификатора inline, который рекомендует компилятору вместо обращения к функции помещать ее код непосредственно в каждую точку вызова. Модификатор inline ставится перед типом функции. Он применяется для коротких функций, чтобы снизить накладные расходы на вызов.

Директива inline носит рекомендательный характер и выполняется компилятором по мере возможности.

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

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

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

Пример функции, возвращающей сумму двух целых величин:

#include <iostream>
using namespace std;
int sum(int a, int b);	// объявление функции
int main(){
	int a = 2, b = 3, c, d;
	c = sum(a, b);	//вызов функции
	cin >> d;
	cout << sum(c, d);  // вызов функции
}
int sum(int a, int b)	// определение функции
{return (a+b);}

Пример функции, выводящей на экран поля переданной ей структуры:

#include <iostream>
using namespace std;
struct Worker
{		
	char fio[30];
	int date, code;
	float salary;
};
void print_worker(Worker);	//объявление функции
int main()
{
Worker stuff[100];
...	/* формирование массива stuff */
for (int i = 0; i<100; i++)
  print_worker(stuff[i]); /*	вызов функции */
}
void print_worker(Worker w)	//определение функции
	{cout << w.fio << ' ' 
		  << w.date << ' ' 
		  << w.code << ' ' 
		  << w.salary;}

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

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

#include <iostream>
using namespace std;
void f(int a)
{
cout << "n  m\n";	
while (a--)
  {
  static int n = 0;
  int m = 0;
  cout << n++ << ' ' 
	   << m++ << '\n';
	}
}
int main(){ f(3);}

Статическая переменная n размещается в сегменте данных и инициализируется один раз при первом выполнении оператора, содержащего ее определение. Программа выведет на экран:

n m
0 0
1 0
2 0

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

Глобальные переменные

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

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

Возвращаемое значение

Возврат из функции в вызвавшую ее функцию реализуется оператором

return [ выражение ];

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

Примеры:

int f1(){ return 1; } 	//правильно
void f2(){ return 1; }	//неправильно, f2 не должна возвращать значение
double f3(){ return 1; }	//правильно, 1 преобразуется к типу double

ВНИМАНИЕ

Нельзя возвращать из функции указатель на локальную переменную.

Пример:

int* f() 
{
int a = 5;
return &a;     // нельзя!
}
< Лекция 3 || Лекция 4: 1234 || Лекция 5 >
Dana Kanatkyzi
Dana Kanatkyzi
Задача на функции
Юрий Семевский
Юрий Семевский
Россия, Санкт-Петербург
Александр Богдашов
Александр Богдашов
Россия