- •3.8. Упражнения 49
- •Введение
- •1. Базовые элементы
- •1.1. Комментарии
- •1.2. Функция «main»
- •1.3. Идентификаторы и пространства имен
- •1.4. Типы
- •1.5. Переменные
- •1.7. Константы
- •1.6. Преобразование типов
- •1.8. Потоковый ввод – вывод
- •1.9. Операции
- •1.9.1. Арифметические операции
- •1.9.2. Поразрядные операции
- •1.9.3. Условный оператор
- •1.9.4. Операции отношения
- •1.9.5. Логические операции
- •1.10. Стандартные математические функции
- •1.11. Упражнения
- •2. Базовые конструкции
- •2.1 Ветвление
- •2.1.1. Конструкция «if – else»
- •2.1.2. Конструкция «switch»
- •2.2. Циклы
- •2.2.1. Цикл «for»
- •2.2.2. Цикл «while»
- •2.2.3. Цикл «do – while»
- •2.2.4. Операторы циклов
- •2.2.5. Вложенность
- •2.3. Упражнения
- •2.3.1. Ветвления
- •2.3.2. Циклы
- •2.3.3. Вложенность
- •3. Указатели. Массивы. Структуры
- •3.1. Указатели
- •3.2. Массивы
- •3.2.1. Статические массивы
- •3.2.2. Динамические массивы
- •3.4. Ссылки
- •3.5. Структуры
- •3.6. Объединение
- •3.7. Переопределение типов
- •3.8. Упражнения
- •3.8.1. Статические и динамические массивы
- •3.8.2. Многомерные массивы
- •3.8.3. Строки
- •4. Функции
- •4.1. Простые функции
- •4.2. Рекурсия
- •4.3. Указатели и ссылки
- •4.3.1. Передаваемые параметры
- •4.3.2. Возвращаемые значения
- •4.3.3. Ссылки и структуры в функциях
- •4.3.4. Указатели и массивы в функциях
- •4.3.5. Указатели и ссылки на функцию
- •4.4. Шаблоны функций
- •4.5. Упражнения
- •4.5.1. Простые функции
- •4.5.2. Параметры – ссылки и параметры — указатели
- •5. Стандартные классы
- •5.1. Класс «pair»
- •5.2. Класс «complex»
- •5.3. Класс «string»
- •5.4. Контейнеры. Алгоритмы. Итераторы
- •5.5. Класс «vector»
- •5.6. Упражнения
- •5.6.1. Класс «string»
- •5.6.2. Класс «vector»
- •6. Файловый ввод – вывод
- •6.1. Операции
- •6.2. Методы
- •6.3. Флаги
- •6.4. Двоичный режим
- •6.5. Упражнения
- •Ллитература
4. Функции
4.1. Простые функции
Функции применяются для разделения больших задач на подзадачи и используются для замены часто повторяющихся участков кода. Такой подход скрывает детали реализации тех или иных действий, что делает код более понятным. Применение функций также способствует более легкому сопровождению кода и его уменьшению.
Часто в процессе программирования прибегают к такому методу, как нисходящее проектирование. При таком подходе, задача с самого начала реализации разбивается на подзадачи, каждая из которых, в свою очередь, также разбивается на подзадачи и т.д. В итоге, конкретные действия реализуются на последних этапах написания кода.
Каждая функция имеет свое собственное имя. Параметры, передаваемые функции, должны содержаться в скобках и следовать через запятую. Результатом функции является значение определенного типа, называемое возвращаемым, за исключением того случая, когда функция объявлена, как вовсе не возвращающая значения при помощи «void». Все выполняемые функцией действия – тело функции – заключаются в фигурные скобки. Совокупность имени функции, типа возвращаемого значения, списка параметров и выполняемых ей действий называется определением. Функция может быть определена только один раз, за исключением «inline» – функций (встраиваемых). Помимо определения, функция может иметь объявление – прототип – совокупность типа возвращаемого значения, имени функции и списка параметров, которое может быть не единственным.
Вызов функции для исполнения происходит посредством оператора вызова «()», при этом внутри скобок должны быть перечислены фактические параметры функции – передаваемые ей значения.
Листинг 4.1. Функция вывода элементов массива.
#include <iostream>
using namespace std;
//Определение функции.
void array_out (int iar[], const int N)
{
for (int i = 0; i < N; i++)
cout << iar[i] << endl;
}
int main (void)
{
const int N = 10;
int x[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//вызов функции, невозвращающей значения и принимающей
//значения указателя на первый элемент массива и его размер;
array_out(x, N);
return 0;
}
Вызов функции может быть выполнен двумя способами. Если объявление содержит спецификатор «inline», то тело функции подставляется в место ее вызова, иначе – происходит обычный вызов с передачей управления, при этом, «inline» – функции всегда должны иметь определение. Однако, этот спецификатор является только «рекомендацией» компилятору, который может и не встроить данную функцию в место ее вызова. Функция должна быть объявлена до своего вызова, однако может быть определена после него. Оператор «return» выполняет возврат значения из функции, если функция не имеет в качестве возвращаемого значения тип «void», а также осуществляет выход из функции – возврат управления. С случае с «void» оператор «return» не обязателен.
Листинг 4.2. Встраиваемые функции.
#include <iostream>
using namespace std;
//Объявление функции – прототип.
int eq (int a, int b);
//Определение встраиваемых функций.
inline int abs (int a) { return a > 0 ? a : -a; }
inline int max (int a, int b) { return a > b ? a : b; }
inline int min (int a, int b) { return a < b ? a : b; }
int main (void)
{
int x = 10;
int y = -10;
cout << abs(y) << endl;
cout << max(x, y) << endl;
cout << min(x, y) << endl;
cout << eq(x, y) << endl;
cout << eq(abs(x), abs(y)) << endl;
return 0;
}
//Определение объявленной ранее функции.
int eq (int a, int b)
{
return max(a, b) == min(a, b) ? 1 : 0;
}
В качестве параметров могут передаваться как переменные, так и константы. Проверка соответствия и преобразования типов выполняются также, как и при инициализации переменных или вычислении значений каких-либо выражений. Переменные, хранящие входные параметры, существуют до конца выполнения функции, после чего уничтожаются. Аналогичным поведением обладают любые переменные, объявленные внутри функции. Исключением являются только те, что объявлены со спецификатором «static». В связи с тем, что память для таких переменных выделяется в области «heap», время их жизни увеличивается до конца выполнения программы, при этом очередной вызов функции будет иметь дело со значением этой переменной, заданным при предыдущем вызове.
Зачастую возникают ситуации, когда необходимо совершить аналогичные действия над данными различных типов. В таких ситуациях используют перегрузку – использование одного имени для различных операций, так, операция «+» используется для различных встроенных типов. Подобный подход удобен для восприятия и легко может быть распространен на функции – перегруженные функции отличаются только списком параметров, и среди одноименных будет выбрана та, чьи формальные параметры наиболее точно соответствуют фактическим.
Язык С++ предоставляет также возможность задавать значения параметров по умолчанию. Эти значения будут использованы в качестве параметров в том случае, если фактические параметры не указаны.
Листинг 4.3. Перегрузка функций.
#include <iostream>
using namespace std;
//Функция вывода целых значений значений.
void output (int val, int base = 10)
{
if (base == 10)
cout << dec << val << endl;
if (base == 16)
cout << hex << val << endl;
}
//Функция вывода дробных значений значений.
void output (double val, …)
{
cout << fixed << val << endl;
}
int main (void)
{
int base, ival;
cin >> ival >> base;
//вызов целочисленной версии с параметром по умолчанию;
output( ival );
//вызов целочисленной версии с заданным параметром;
output( ival, base );
double dval;
cin >> dval;
//вызов дробной версии;
output( dval );
return 0;
}
