Лекция 8
1/41
211.50K
Category: programmingprogramming

Функции: понятие, описание. Структура программы. Передача параметров и возврат значений

1. Лекция 8

Функции: понятие, описание.
Структура программы.
Передача параметров и возврат значений.

2. Основные понятия и определения

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

3. Основные понятия и определения

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

4. Основные понятия и определения

Интерфейс функции

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

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

5. Виды функций

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

6. Описание функций

Описание функции на языке С осуществляется в любом месте
программы вне описания других функций и состоит из трех
элементов:
прототип функции;
заголовок функции;
тело функции.

7. Прототип функции

Прототип функции – необязательная часть описания функции,
предназначенная для объявления некоторой функции,
интерфейс которой соответствует данному прототипу.
Объявление прототипа имеет следующий вид:
возвращаемый тип имя(список типов формальных параметров);

8. Параметры функции

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

9. Прототип функции

Примеры прототипов:
int func(int, double, double);
void func(int, char *);
double func(void);

10. Заголовок функции

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

11. Заголовок функции

Каждый элемент (формальный параметр) имеет следующий
формат объявления:
тип имя
Примеры заголовков функций:
int func(int i, double x, double y)
void func(int ind, char *string)
double func(void)

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

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

13. Пример

Реализация функции вычисления факториала числа.
double factorial(unsigned);
...
double factorial(unsigned num)
{
double fact = 1.0;
for(unsigned i=1;i<=num;i++)
fact *= (double)i;
return fact;
}

14. Пример

Вызов функции вычисления факториала представлен в
следующем фрагменте программы:
unsigned n = 8;
double vals[2] = {0.0};
...
//Константа 5 – фактический параметр
vals[0] = factorial(5);
//Переменная n – фактический параметр
vals[1] = factorial(n);
...

15. Пример

Подсчет количества положительных элементов в целочисленном
массиве.
unsigned positive(int [], unsigned);
...
unsigned positive(int arr[], unsigned num)
{
unsigned count = 0;
for(unsigned i=0;i<num;i++)
if(arr[i] > 0) count++;
return count;
}

16. Пример

Вызов функции подсчета положительных элементов в
целочисленном массиве представлен в следующем
фрагменте программы:
unsigned n = 10;
int array[n];
...
unsigned cnt = positive(array,n);
...

17. Структура программы

1: подключение библиотек.
2: объявление глобальных пользовательских типов
данных и переменных.
3: объявление прототипов пользовательских
функций.
4: реализация функции main.
5: реализация (описание заголовков и тел)
пользовательских функций.

18. Пример

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

19. Пример

#include <stdio.h>
#include <string.h>
void division(double,double);
int main(int argc, char *argv[])
{
do{
char str[80];
printf("Введите два числа для/
вычислений\nили пустую/
строку для выхода\n>:");
gets(str);
if(strcmp(str,"") == 0) break;
double x,y;
sscanf(str,"%lf %lf",&x,&y);
division(x,y);
}while(1);
return 0;
}
double max(double x, double y)
{
return (x>y)?x:y;
}
double min(double x, double y)
{
return (x<y)?x:y;
}
void division(double x, double y)
{
double res = max(x,y)/min(x,y);
printf("Результат: %lf\n",res);
}

20. Функциональная схема программы

Функция main
Функция I-го уровня

Функция I-го уровня
Функция II-го уровня

Функция II-го уровня


21. Пример

main
division
max
min

22. Возвращаемое значение функции

Для реализации возврата значения и завершения выполнения
функции используется оператор завершения функции,
который относится к группе операторов управления, не
рассматривался ранее. Синтаксис использования оператора
завершения функции:
return выражение;
Если функция не возвращает никакого значения (в заголовке
указан тип void), то оператор возврата указывается без
какого-либо выражения:
return;

23. Пример

Функция, определяющую количество корней
квадратного уравнения (целочисленное значение),
заданного коэффициентами a, b и c (формальные
параметры функции):
int NumberOfRoots(double a, double b, double c)
{
double descr = b*b – 4.0*a*c;
if(descr < 0) return 0;
else if(descr > 0) return 2;
else return 1;
}

24. Пример

double descr=b*b–4.0*a*c;
if(descr<0) return 0;
else if(descr>0) return 2;
return 1;
double descr=b*b–4.0*a*c;
int num = 1;
if(descr<0) num = 0;
else if(descr>0) num = 2;
return num;

25. Возврат значений сложных типов

Возврат значений сложных типов (структур и объединений)
возможен только в стандарте С99.
В более ранних версиях языка возврат в качестве значений
структур или объединений невозможен.
Возвращать в качестве значений массивы в языке С нельзя. Для
этого можно использовать возврат указателя на массив.

26. Параметры функции

Параметры функции могут быть константными: их невозможно
изменить. Для описания такого параметра перед его типом
указывается ключевое слово const.
Пример:
int Length(const char *str)
{
int len = 0;
for(char *ptr = str;*ptr!=0;ptr++) len++;
return len;
}

27. Передача параметров по значению и по ссылке

В языках программирования высокого уровня
реализованы два механизма передачи
параметров:
по значению;
по ссылке.

28. Передача по значению

Механизм передачи параметра по значению заключается в
следующем: в вызываемую функцию передается значение
фактического параметра.
void Inc(int a) { a++; }
int main (int argc, char *argv[])
{
int val = 0;
printf(“Значение: %d\n”,val);
Inc(val);
printf(“Значение: %d\n”,val);
return 0;
}

29. Передача по ссылке

В языке С механизм передачи параметра по ссылке
реализован посредством указателей.
void Inc(int *a) { (*a)++; }
int main (int argc, char *argv[])
{
int val = 0;
printf(“Значение: %d\n”,val);
Inc(&val);
printf(“Значение: %d\n”,val);
return 0;
}

30. Передача по ссылке

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

31. Пример

Реализация функции поиска максимального и
минимального значения в целочисленном массиве.
void GetMinMax(int arr[], int n, int *min, int *max)
{
*min = arr[0]; *max = arr[0];
for(int i=1;i<n;i++){
if(arr[i] > *max) *max = arr[i];
if(arr[i] < *min) *min = arr[i];
}
}

32. Пример

Использование данной функции продемонстрировано в следующем
фрагменте программы:
int main(int argc, char *argv[])
{
int n;
... //Ввод переменной n
int array[n];
... //Ввод массива array
int maxel, minel;
GetMinMax(array,n,&minel,&maxel);
printf(“Минимум массива: %d\n”, minel);
printf(“Максимум массива: %d\n”, maxel);
...
}

33. Массивы как параметры функции

Так как в языке С имя массива является указателем на массив, то массивы в языке С
передаются только по ссылке.
void ProcArray(int arr[], int n)
{
for(int i=0;i<n;i++) arr[i]++;
}
int main(int argc, char *argv[])
{
int array[] = {0,1,2,3,4,5,6,7,8,9};
int num = sizeof(array)/sizeof(int);
for(int i=0;i<num;i++) printf("%d ",array[i]); //0 1 2 3 4 5 6 7 8 9
puts("");
ProcArray(array,num);
for(int i=0;i<num;i++) printf("%d ",array[i]); //1 2 3 4 5 6 7 8 9 10
puts("");
return 0;
}

34. Массивы как параметры функции

Массив можно передавать в параметрах используя синтаксис указателя.
void ProcArray(int *arr, int n)
{
for(int i=0;i<n;i++) arr[i]++;
}
int main(int argc, char *argv[])
{
int array[] = {0,1,2,3,4,5,6,7,8,9};
int num = sizeof(array)/sizeof(int);
for(int i=0;i<num;i++) printf("%d ",array[i]);
puts("");
ProcArray(array,num);
for(int i=0;i<num;i++) printf("%d ",array[i]);
puts("");
return 0;
}

35. Массивы как параметры функции

Массив в параметрах функции может быть объявлен как константный.
Значения элементов этого массива нельзя изменить внутри этой
функции, обратившись к ним через имя этого массива. Но можно
через дополнительный не константный указатель, установленный
на массив с явным приведением типа.
void ProcArray(const int arr[], int n)
{
for(int i=0;i<n;i++) arr[i]++;
//Ошибка
int *arrptr1 = arr;
//Ошибка
int *arrptr2 = (int *)arr;
//Корректно
for(int i=0;i<n;i++) arrptr2[i]++; //Корректно
}

36. Массивы как параметры функции

Передача в параметрах многомерных массивов (две и более
размерности) осуществляется иначе.
Неправильно:
void ProcArray(int arr[][], int n, int m)
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
arr[i][j]++;
}

37. Массивы как параметры функции

Правильный способ
void ProcArray(int n, int m, int arr[n][m])
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
arr[i][j]++;
}

38. Строки как параметры функции

Строки в языке С в качестве параметров передаются с использованием синтаксиса
указателя на символьный тип.
void ProcString(char *str)
{
for(int i=0;str[i]!=0;i++)
if(islower(str[i])) str[i] = 'A' + (str[i] - 'a');
else if(isupper(str[i])) str[i] = 'a' + (str[i] - 'A');
}
int main(int argc, char *argv[])
{
char string[] = "Hello World!";
puts(string);
//Hello World!
ProcString(string);
puts(string);
//hELLO wORLD!
return 0;
}

39. Строки как параметры функции

При передаче в качестве параметра массива строк необходимо использовать способ
передачи двумерных массивов. Или возможен следующий вариант:
void ProcString(char *str[], int n)
{
for(int i=0;i<n;i++){
for(int j=0;str[i][j]!=0;j++)
if(islower(str[i][j])) str[i][j] = 'A' + (str[i][j] - 'a');
else if(isupper(str[i][j])) str[i][j] = 'a' + (str[i][j] - 'A');
}
}
int main(int argc, char *argv[])
{
char string[][20] = {"One","Two","Three","Four","Five"};
char *strs[] = {string[0],string[1],string[2],string[3],string[4]};
for(int i=0;i<5;i++) puts(string[i]);
ProcString(strs,5);
for(int i=0;i<5;i++) puts(string[i]);
return 0;
}

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

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

41. Нижний уровень передачи параметров

В языке С по умолчанию используется метод передачи в
обратном порядке. Если необходимо изменить направление
передачи параметров или явно его указать, то перед
именем функции указывают одно из ключевых слов:
_stdcall (или __stdcall) – передача параметров в прямом
порядке;
_cdecl (или __cdecl) – передача параметров в обратном
порядке.
Например:
int __cdecl Function(int ind, double x, double y);
char * __stdcall Function(char *strs[], int num);
English     Русский Rules