ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4251
Скачиваний: 28
Глава 6. Функции
81
В качестве примера определим функцию, которая возвращает
сумму двух чисел.
int add(int x, int y) { return x + y; }
Если функция не возвращает никакого значения, то для выхода из
функции используется инструкция
return
без выражения. Если
выход из функции, не возвращающей значения, происходит как
выход из блока, содержащего тело функции, то в этом случае ин-
струкцию
return
можно опустить. Например, следующая функ-
ция напечатает сумму двух чисел:
void print(int x, int y)
{
printf("x + y = %d\n", x + y);
}
Параметры функции можно рассматривать как локальные пере-
менные, которые видны только в теле функции. Поэтому пара-
метр функции не может иметь тип
void
. Однако в качестве пара-
метра допускается указатель на тип
void
. Значения параметров
можно изменять в теле функции, если они не имеют квалифика-
тора
const
. Например, можно написать следующую функцию:
int inc(int n) { return ++n; }
которая возвращает значение
n+1
. Заметим, что функция:
int inc(int n) { return n++; }
вернет значение
n
.
6.3. Стандартные функции
Язык программирования C содержит библиотеку стандартных
функций, которую можно подключить к программе на этапе соз-
дания исполняемого файла. Как это делается, зависит от среды
разработки. Как правило, библиотека стандартных функций язы-
ка программирования C, так же как и стандартная библиотека
языка программирования С++, подключается к проекту по умол-
чанию.
Часть I. Язык программирования С
82
Для того чтобы в программе можно было использовать стандарт-
ные функции, нужно объявить их прототипы. Прототипы стан-
дартных функций содержатся в специальных файлах, которые
имеют расширение h и называются
заголовочными файлами
.
Каждый заголовочный файл содержит объявления только тех
функций и переменных, которые предназначены для решения
одной группы задач.
Для вставки прототипов функций в текст программы использу-
ется директива препроцессора
#include
, которая описана в
разд. 9.5
. Например, вставить в программу прототипы стандарт-
ных функций ввода/вывода можно следующим образом:
#include <stdio.h>
Подробно использование стандартных функций языка програм-
мирования С рассмотрено в
части III
. А в
части IV
рассмотрена
стандартная библиотека языка программирования С++.
Отметим, что при разработке программ программист может соз-
давать свои заголовочные файлы, куда он помещает объявления
своих функций и переменных, используемые в разных исходных
файлах своей программы.
6.4. Вызов функции
Функция должна быть объявлена перед своим вызовом. Вызов
функции имеет следующий вид:
имя_функции(список_аргументов)
и называется
оператором вызова функции
. Этот оператор воз-
вращает R-value.
Список_аргументов
содержит операнды операто-
ра вызова функции, которые перечисляются через запятую, могут
быть произвольными выражениями и называются
аргументами
функции
. Приоритет оператора вызова функции совпадает с при-
оритетом оператора индексирования и постфиксных операторов
инкремента и декремента. Ассоциативность этого оператора —
слева направо.
Аргументы функции используются для инициализации парамет-
ров функции, во время которой может выполняться неявное при-
ведение типов. Порядок вычисления аргументов функции не оп-
Глава 6. Функции
83
ределен. Однако до передачи управления в тело функции все по-
бочные эффекты, возникающие при вычислении аргументов
функции, завершаются. Особенно отметим, что аргументы пере-
даются в функцию по значению. То есть значения аргументов пе-
реписываются в параметры функции. Так как значение аргумента
копируется в тело функции, то сам аргумент изменить в теле
функции невозможно. После инициализации параметров функции
происходит выполнение тела функции. В листинге 6.1 приведена
программа, в которой вызывается функция сложения двух чисел.
Листинг 6.1. Примеры вызова функции
#include <stdio.h>
int add(int x, int y) { return x + y; }
int main(void)
{
int z;
z = add(1, 2); /* вызываем функцию */
printf("z = %d\n", z); /* печатаем результат */
/* можно вызвать функцию и так */
printf("1 + 2 = %d\n", add(1, 2));
/* можно также и так, но в этом случае непонятно зачем */
add(1, 2);
return 0;
}
Для того чтобы функция могла изменить значения переменных в
вызывающей ее функции, она должна получить в качестве аргу-
ментов указатели на эти переменные. В листинге 6.2 приведена
функция
swap
, выполняющая обмен значений, на которые указы-
вают аргументы.
Листинг 6.2. Передача указателей в качестве аргументов функции
#include <stdio.h>
void swap(int* x, int* y)
Часть I. Язык программирования С
84
{
int t;
t = *x;
*x = *y;
*y = t;
}
int main(void)
{
int x = 1, y = 2;
swap(&x, &y);
printf("x = %d y = %d\n", x, y); /* x = 2, y = 1 */
return 0;
}
6.5. Передача массивов в функции
Имя статического массива это константный указатель на его пер-
вый элемент. Поэтому массивы передаются в функции через ука-
затели. Например, следующая функция увеличивает значение
элементов массива на единицу.
void f(int a[3])
{
int i;
for (i = 0; i < 3; ++i)
++a[i];
}
Здесь диапазон индекса массива в параметре функции не имеет
значения, т. к. все равно в функцию передается только указатель.
Поэтому возможны также следующие способы объявления мас-
сива как параметра функции:
int f(int a[]);
или:
int f(int* const a);
Но в этом случае диапазон индекса лучше указать, т. к. он явно
указывает границы диапазона. Дело обстоит сложнее, если функ-
Глава 6. Функции
85
ция должна работать с массивами, диапазон индекса которых не
фиксирован. Так как указатель на массив не содержит информа-
ции о диапазоне индекса, то его нужно передавать в качестве
второго параметра такой функции. Например, следующая функ-
ция увеличивает на единицу значение каждого элемента произ-
вольного одномерного целочисленного массива:
void f(int a[], int n)
{
int i;
for (i = 0; i < n; ++i)
++a[i];
}
Вызов этой функции будет выглядеть следующим образом:
int a[5] = {1, 2, 3, 4, 5};
f(a, 5);
При передаче многомерного массива как параметра функции
нужно указать его полный тип, при этом разрешается опустить
диапазон первого индекса. Значения диапазонов остальных ин-
дексов многомерного массива необходимо знать компилятору
для того, чтобы он мог правильно вычислить смещение к элемен-
там массива. Например, следующая функция увеличивает на еди-
ницу значение каждого элемента двумерного массива:
void f(int a[2][2])
{
int i, j;
for (i = 0; i < 2; ++i)
for (j = 0; j < 2; ++j)
++a[i][j];
}
Для передачи произвольной многомерной статической матрицы
в функцию необходимо в качестве параметра передать адрес ее
первого элемента. Например, следующая функция увеличивает на
единицу значение каждого элемента произвольной матрицы вто-
рого порядка.