2.1 – Знакомство с функциями в C++

Добавлено 9 апреля 2021 в 19:27

В предыдущей главе мы определили функцию как набор инструкций, которые выполняются последовательно. Хотя это, безусловно, правда, это определение не дает подробного понимания того, почему функции полезны. Давайте обновим наше определение: функция – это многократно используемая последовательность инструкций, предназначенная для выполнения определенной работы.

Вы уже знаете, что каждая программа должна иметь функцию с именем main (именно отсюда программа начинает свое выполнение при запуске). Однако по мере того, как программы становятся всё длиннее и длиннее, становится всё труднее управлять размещением всего кода внутри функции main. Функции позволяют разделить наши программы на небольшие модульные части, которые легче организовать, тестировать и использовать. Большинство программ используют множество функций. Стандартная библиотека C++ поставляется с множеством уже написанных функций, которые вы можете использовать, но также часто можно писать и свои собственные. Функции, которые вы пишете сами, называются пользовательскими функциями.

Рассмотрим случай, который может иметь место в реальной жизни: вы читаете книгу и вспоминаете, что вам нужно позвонить по телефону. Вы помещаете закладку в свою книгу, совершаете телефонный звонок, а когда заканчиваете телефонный звонок, вы возвращаетесь в место, которое отметили закладкой, и продолжаете читать книгу с того места, где остановились.

Программы на C++ могут работать точно так же. Программа будет последовательно выполнять инструкции внутри одной функции, пока не обнаружит вызов другой функции. Вызов функции – это выражение, которое говорит CPU прервать текущую функцию и выполнить другую функцию. CPU «помещает закладку» в текущую точку выполнения, а затем вызывает (выполняет) функцию, указанную в вызове функции. Когда вызываемая функция завершается, CPU возвращается в точку, отмеченную закладкой, и возобновляет выполнение.

Функция, инициирующая вызов функции, называется вызывающей функцией или caller, а вызываемая функцияcallee.

Пример пользовательской функции

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

тип_возвращаемого_значения идентификатор() // идентификатор заменяется именем вашей функции
{
    // ваш код здесь
}

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

Вот пример программы, которая показывает, как определяется и вызывается новая функция:

#include <iostream> // для std::cout
 
// Определение пользовательской функции doPrint()
void doPrint() // doPrint() - это вызываемая функция в этом примере
{
    std::cout << "In doPrint()\n";
}
 
// Определение функции main()
int main()
{
    std::cout << "Starting main()\n";
    // Прерываем main(), вызывая функцию doPrint(). main() - это вызывающая функция (caller).
    doPrint(); 
    // эта инструкция выполняется после завершения doPrint()
    std::cout << "Ending main()\n";
 
    return 0;
}

Эта программа создает следующий вывод:

Starting main()
In doPrint()
Ending main()

Эта программа начинает выполнение с начала функции main, и первая строка, которая будет выполняться, выводит текст Starting main().

Вторая строка в main – это вызов функции doPrint. Мы вызываем функцию doPrint, добавляя пару скобок к имени функции, например: doPrint(). Обратите внимание: если вы забудете скобки, ваша программа может не компилироваться (а если это произойдет, функция не будет вызываться).

Предупреждение


Не забывайте при вызове функции ставить круглые скобки () после имени функции.

Поскольку был выполнен вызов функции, выполнение инструкций в main приостанавливается, и выполнение переходит к началу вызываемой функции doPrint. Первая (и единственная) строка в doPrint печатает текст In doPrint(). Когда doPrint завершается, выполнение возвращается к вызывающей функции (здесь: функция main) и возобновляется с того места, где оно было остановлено. Следовательно, следующая инструкция, выполняемая в main, выводит на печать Ending main().

Вызов функций более одного раза

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

#include <iostream> // для std::cout
 
void doPrint()
{
    std::cout << "In doPrint()\n";
}
 
// Определение функции main()
int main()
{
    std::cout << "Starting main()\n";
    doPrint(); // doPrint() вызывается впервые
    doPrint(); // doPrint() вызывается во второй раз
    std::cout << "Ending main()\n";
 
    return 0;
}

Эта программа создает следующий вывод:

Starting main()
In doPrint()
In doPrint()
Ending main()

Так как doPrint вызывается из main дважды, doPrint выполняется дважды, и In doPrint() печатается дважды (один раз для каждого вызова).

Функции, вызывающие функции, вызывающие функции

Вы уже видели, что функция main может вызывать другую функцию (например, функцию doPrint в приведенном выше примере). Любая функция может вызывать любую другую функцию. В следующей программе функция main вызывает функцию doA, которая вызывает функцию doB:

#include <iostream> // для std::cout
 
void doB()
{
    std::cout << "In doB()\n";
}
 
 
void doA()
{
    std::cout << "Starting doA()\n";
 
    doB();
 
    std::cout << "Ending doA()\n";
}
 
// Определение функции main()
int main()
{
    std::cout << "Starting main()\n";
 
    doA();
 
    std::cout << "Ending main()\n";
 
    return 0;
}

Эта программа создает следующий вывод:

Starting main()
Starting doA()
In doB()
Ending doA()
Ending main()

Вложенные функции не поддерживаются

В отличие от некоторых других языков программирования, в C++ функции не могут быть определены внутри других функций. Следующая программа не является корректной:

#include <iostream>
 
int main()
{
    int foo() // Запрещено: эта функция вложена внутри функции main()
    {
        std::cout << "foo!\n";
        return 0;
    }
 
    foo(); // вызов функции foo()
    return 0;
}

Правильный способ написать приведенную выше программу:

#include <iostream>
 
int foo() // больше не внутри main()
{
    std::cout << "foo!\n";
    return 0;
}
 
int main()
{
    foo();
    return 0;
}

Небольшой тест

Вопрос 1

Как в определении функции называются фигурные скобки и инструкции между ними?

Тело функции


Вопрос 2

Что печатает следующая программа? Не компилируйте ее, просто отследите код самостоятельно.

#include <iostream> // для std::cout
 
void doB()
{
    std::cout << "In doB()\n";
}
 
void doA()
{
    std::cout << "In doA()\n";
 
    doB();
}
 
// Определение функции main()
int main()
{
    std::cout << "Starting main()\n";
 
    doA();
    doB();
 
    std::cout << "Ending main()\n";
 
    return 0;
}

Starting main()
In doA()
In doB()
In doB()
Ending main()

Теги

C++ / CppДля начинающихОбучениеПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.