Слайд 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 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
#include
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}
void division(double x, double y)
{
double res = max(x,y)/min(x,y);
printf("Результат: %lf\n",res);
}
Слайд 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;
}
Слайд 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 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}
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 puts("");
ProcArray(array,num);
for(int i=0;i puts("");
return 0;
}
Слайд 34Массивы как параметры функции
Массив можно передавать в параметрах используя синтаксис указателя.
void
ProcArray(int *arr, int n)
{
for(int i=0;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 puts("");
ProcArray(array,num);
for(int i=0;i puts("");
return 0;
}
Слайд 35Массивы как параметры функции
Массив в параметрах функции может быть объявлен как
константный. Значения элементов этого массива нельзя изменить внутри этой функции, обратившись к ним через имя этого массива. Но можно через дополнительный не константный указатель, установленный на массив с явным приведением типа.
void ProcArray(const int arr[], int n)
{
for(int i=0;i int *arrptr1 = arr; //Ошибка
int *arrptr2 = (int *)arr; //Корректно
for(int i=0;i}
Слайд 36Массивы как параметры функции
Передача в параметрах многомерных массивов (две и более
размерности) осуществляется иначе.
Неправильно:
void ProcArray(int arr[][], int n, int m)
{
for(int i=0;i for(int j=0;j arr[i][j]++;
}
Слайд 37Массивы как параметры функции
Правильный способ
void ProcArray(int n, int m, int arr[n][m])
{
for(int i=0;i for(int j=0;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 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);