У каждой программы должна быть функция с именем main
. С нее программа начинает выполняться при запуске. Но когда программа масштабируется, становится сложнее размещать весь код внутри этой функции. В этом случае используют функции, которые позволяют разделить программы на небольшие модульные части. Их легче организовать, тестировать и использовать.
Большинство программ используют множество функций. Стандартная библиотека C++ поставляется с множеством уже написанных функций, которые вы можете использовать, но также часто можно писать и свои собственные. Функции, которые вы пишете сами, называются пользовательскими функциями.
В этом уроке мы рассмотрим как создавать пользовательские функции.
Представим, что мы читаем книгу и вспоминаем, что нам нужно сделать звонок. Мы оставляем закладку, говорим по телефону и возвращаемся читать книгу с того места, где оставили закладку.
Программы на C++ могут работать так же. Программа будет последовательно выполнять инструкции внутри одной функции, пока не обнаружит вызов другой функции.
Вызов функции — это выражение, которое говорит CPU прервать текущую функцию и выполнить другую. Получается, что CPU «помещает закладку» в текущую точку выполнения, а затем вызывает функцию, указанную в вызове функции. Когда вызываемая функция завершается, CPU возвращается в точку, которая отмечена закладкой, и возобновляет выполнение.
Разберемся как определять пользовательские функции в С++.
Начнем с базового синтаксиса для определения пользовательской функции. В этом уроке все пользовательские функции кроме main
будут иметь следующий вид:
тип_возвращаемого_значения идентификатор(параметры функции) { // идентификатор заменяется именем вашей функции
// ваш код здесь
}
Подробнее о различных частях этого синтаксиса поговорим в следующих уроках. На данный момент идентификатор будет просто заменен именем нашей пользовательской функции. Фигурные скобки и инструкции между ними называются телом функции.
Рассмотрим пример программы, которая показывает, как определяется и вызывается новая функция:
void Greating() {
std::cout << "Hello Code Basics!" << std::endl;
}
int main() {
std::cout << "Starting main()" << std::endl;
// Прерываем main(), вызывая функцию Greating().
Greating();
// эта инструкция выполняется после завершения Greating()
std::cout << "Ending main()" << std::endl;
return 0;
}
Эта программа создает следующий вывод:
Starting main() Hello Code Basics! Ending main()
Программа начинает выполняться с начала функции main
. Первая строка, которая будет выполняться, выводит текст Starting main()
. Вторая строка в main
— это вызов функции Greating()
. Мы вызываем функцию Greating()
, добавляя скобки к имени функции, например: Greating()
. Если забыть про скобки, программа может не компилироваться.
Так как мы вызвали функцию, выполнение инструкций в main
приостанавливается. В итоге выполнение переходит к началу вызываемой функции Greating()
.
Первая и единственная строка в Greating()
печатает текст Hello Code Basics!
. Когда Greating()
завершается, выполнение возвращается к вызывающей функции — здесь: функция main
. Далее оно возобновляется с того места, где остановилось. Получается, следующая инструкция, которая выполняется в main
, выводит на печать Ending main()
.
Полезная особенность функций заключается в том, что их можно вызывать более одного раза в разных частях программы. Вот программа, которая демонстрирует это:
void Greating() {
std::cout << "Hello Code Basics!" << std::endl;
}
int main() {
Greating();
Greating();
return 0;
}
Обратите внимание мы вызываем функцию Greating()
два раза.
Эта программа создает следующий вывод:
Hello Code Basics! Hello Code Basics!
В отличие от некоторых других языков программирования в C++ функции не могут быть определены внутри других функций. Следующая программа не является корректной:
int main() {
void Greating() {
std::cout << "Hello Code Basics!";
}
Greating();
return 0;
}
В коде выше мы попытались определить внутри функции main()
, функцию Greating()
и получили ошибку компиляции:
main.cpp:12:3: error: ‘PrintMoto’ was not declared in this scope 12 | PrintMoto(); | ^~~~~~~~~
Это прежде всего связанно с особенностью языка и выделением памяти.
В этом уроке мы рассмотрели структуру и создание функций. Понятие «создать функцию» имеет много синонимов: «реализовать», «определить» и даже «заимплементить» (от слова implement). Все они встречаются в повседневной практике на работе.
Напишите функцию PrintMoto()
, которая выводит на экран фразу Spring is coming
, и вызовите ее внутри функции main
.
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1#include "test_helper.h"
2
3TEST_CASE("testing solution") {
4 std::string expected = "Spring is coming\n";
5 std::string actual = get_output(sizeof(expected));
6
7 CHECK(actual == expected);
8}
9
Решение учителя откроется через: