Функции, процедуры, рекурсия в С++: 5-я часть гайда по языку программирования
2026-02-21 01:13 Diff

#Руководства

  • 5 июн 2020
  • 0

Разбираемся, как функции помогают сократить код и сделать программу полезнее.

 vlada_maestro / shutterstock

Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.

Это пятая часть из серии статей «Глубокое погружение в C++». В прошлый раз мы узнали, как правильно использовать ввод данных и обрабатывать исключения. Сегодня займёмся функциями и процедурами.

Если код нужно использовать несколько раз, то лучше всего его вывести в подпрограмму — функцию или процедуру. Это позволит значительно сократить объём кода. Давайте рассмотрим вот такую программу:

int name1 = "John"; int name2 = "James"; int name3 = "Jack"; int name4 = "Ivan"; int name5 = "Igor"; int name6 = "Boris"; std::cout << "Hello, " << name1 << "!\n"; std::cout << "Hello, " << name2 << "!\n"; std::cout << "Hello, " << name3 << "!\n"; std::cout << "Hello, " << name4 << "!\n"; std::cout << "Hello, " << name5 << "!\n"; std::cout << "Hello, " << name6 << "!\n";

Программа по очереди приветствует шесть человек. Это относительно небольшой код, но что, если понадобится заменить фразу «Hello, %name%!» на «Hello, %name%! How are you?»? Тогда придётся поменять код в шести местах. А такие сообщения могут выводиться сто или даже тысячу раз.

Подпрограммы как раз и нужны, чтобы избежать таких проблем.

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

Одну функцию мы с вами уже создавали — main (). Она работает как точка входа в каждую программу. Другие функции создаются аналогичным образом:

Вот так это выглядит в коде:

#include <iostream> //Новые функции и процедуры должны создаваться выше функции main() //В круглых скобках указываются аргументы, которые будет принимать функция int sum(int a, int b) { //Используем переданные аргументы, чтобы провести вычисления int result = a + b; //Оператор возврата говорит программе, что функция завершила работу return result; //Всё, что записано после return, не будет выполнено } int main() { //Вызываем функцию с аргументами int result = sum(5, 6); }

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

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

#include <iostream> void printHello(std::string name) { std::cout << "Hello, " << name << "!\n"; } int main() { printHello("Igor"); printHello("Boris"); }

Вот что выведет такая программа:

Функция main () автоматически возвращает значение, поэтому отдельно прописывать return не обязательно. Программа вернёт 0, если она выполнилась успешно, или другое число в зависимости от ошибки.

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

#include <iostream> void printHello() { //Переменная name объявлена в другой функции, поэтому у printHello() нет к ней доступа //Запуск такого кода приведёт к ошибке std::cout << "Hello, " << name << "!\n"; } int main() { std::string name = "Igor"; printHello(); }

Если переменная создаётся внутри какого-либо блока {}, то она будет доступна только в этом и во всех вложенных блоках; такие переменные называются локальными.

Если вы хотите, чтобы какая-нибудь переменная была доступна везде, то её нужно объявить за пределами каких-либо блоков; такие переменные называются глобальными:

#include <iostream> //Глобальные переменные создаются вне функций std::string name; void printHello() { std::cout << "Hello, " << name << "!\n"; } int main() { name = "Igor"; printHello(); }

Однако использовать глобальные переменные не рекомендуется, потому что вам будет сложно отслеживать изменения и влиять на результат работы программы. Единственное исключение — это константы, которые нужно делать глобальными, потому что они не меняются.

Рассмотрим, что происходит, когда вы передаёте аргумент в функцию. Допустим, есть вот такой код:

#include <iostream> void sum(int a) { a = a + 500; } int main() { int a = 5; sum(a); std::cout << a << "\n"; }

Можно подумать, что в результате программы мы увидим число 505, но это неверно. Дело в том, что функции в качестве аргументов принимают не сами переменные, а их значения. То есть в sum () попала не ячейка памяти, а число 5, которое находилось в этой ячейке. Учитывайте это, когда пишете программы.

Это касается только примитивных типов данных. Ссылочные типы ведут себя иначе.

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

Чтобы понять, что такое рекурсия, нужно понять, что такое рекурсия

Чаще всего рекурсия объясняется на примере факториалов (не путать с фракталами):

#include <iostream> int f(int n) { if(n < 0) { return 0; } else if (n == 0) { return 1; } else { return n * f(n - 1); } } void printFactorial(int n) { int a = f(n); std::cout << n << "! = " << a << "\n"; } int main() { printFactorial(1); printFactorial(2); printFactorial(3); printFactorial(4); printFactorial(5); printFactorial(6); printFactorial(7); printFactorial(8); printFactorial(9); printFactorial(10); }

Вот факториалы чисел от 1 до 10:

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

На практике применение этой особенности можно увидеть при рекурсивном удалении папок. Функция удаления должна работать так:

  1. Сканирует указанную папку.
  2. Удаляет все файлы из этой папки.
  3. Сканирует папки внутри этой папки и выполняет предыдущие шаги для каждой из них.

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

  1. Называйте их так, чтобы было сразу понятно, что они делают. При этом лучше использовать повелительное наклонение, то есть напечатайФакториал (), а не печатьФакториала ().
  2. Делайте функции как можно меньше и универсальнее.
  3. Если есть вероятность, что часть кода может повториться несколько раз, то сразу выносите её в отдельную функцию.

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

Бесплатный курс по Python ➞
Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу