Главная страница
Навигация по странице:

  • Урок №14. Почему функции полезны и как их эффективно использовать

  • Зачем использовать функции

  • Эффективное использование функций

  • Урок №15. Локальная область видимости

  • Область видимости переменной

  • Локальная область видимости предотвращает возникновение конфликтов имён

  • Правило: Имена, которые используются внутри функции (включая параметры), доступны/видны только внутри этой же функции. ravesli.com 95 Тест

  • С самоучитель. Уроки по с ravesli com 2 предисловие


    Скачать 2.56 Mb.
    НазваниеУроки по с ravesli com 2 предисловие
    АнкорС самоучитель
    Дата21.02.2022
    Размер2.56 Mb.
    Формат файлаpdf
    Имя файлаprobnik_uroki_cpp_ravesli.pdf
    ТипУрок
    #369439
    страница6 из 6
    1   2   3   4   5   6
    Как работают параметры и возвращаемые значения функций?
    Используя параметры и возвращаемые значения, мы можем создавать функции, которые могут принимать и обрабатывать данные, а затем возвращать результат обратно в caller.
    Например, простая функция, которая принимает два целых числа и возвращает их сумму:
    #include
    // Функция add() принимает два целых числа в качестве параметров и возвращает
    их сумму
    // Значения a и b определяет caller
    int add
    (
    int a
    ,
    int b
    )
    {
    return a
    +
    b
    ;
    }
    // Функция main() не имеет параметров
    int main
    ()
    {
    std
    ::
    cout
    <<
    add
    (
    7
    ,
    8
    )
    <<
    std
    ::
    endl
    ;
    // аргументы 7 и 8 передаются в
    функцию add()
    return
    0
    ;
    }
    При вызове функции add(), параметру a присваивается значение 7, а параметру b — 8.
    Затем функция add() вычисляет их сумму и возвращает результат обратно в main(). Затем уже результат выводится на экран.
    Результат выполнения программы выше:
    15
    Ещё примеры
    Рассмотрим ещё несколько вызовов функций:
    #include
    ravesli.com
    85 int add
    (
    int a
    ,
    int b
    )
    {
    return a
    +
    b
    ;
    }
    int multiply
    (
    int c
    ,
    int d
    )
    {
    return c
    *
    d
    ;
    }
    int main
    ()
    {
    std
    ::
    cout
    <<
    add
    (
    7
    ,
    8
    )
    <<
    std
    ::
    endl
    ;
    // внутри функции add(): a = 7, b = 8,
    значит a + b = 15
    std
    ::
    cout
    <<
    multiply
    (
    4
    ,
    5
    )
    <<
    std
    ::
    endl
    ;
    // внутри функции multiply(): c =
    4, d = 5, значит c * d = 20
    // Мы можем передавать целые выражения в качестве аргументов
    std
    ::
    cout
    <<
    add
    (
    2
    +
    3
    ,
    4
    *
    5
    )
    <<
    std
    ::
    endl
    ;
    // внутри функции add(): a =
    5, b = 20, значит a + b = 25
    // Мы можем передавать переменные в качестве аргументов
    int x
    =
    4
    ;
    std
    ::
    cout
    <<
    add
    (
    x
    ,
    x
    )
    <<
    std
    ::
    endl
    ;
    // будет 4 + 4
    std
    ::
    cout
    <<
    add
    (
    1
    ,
    multiply
    (
    2
    ,
    3
    ))
    <<
    std
    ::
    endl
    ;
    // будет 1 + (2 * 3)
    std
    ::
    cout
    <<
    add
    (
    1
    ,
    add
    (
    2
    ,
    3
    ))
    <<
    std
    ::
    endl
    ;
    // будет 1 + (2 + 3)
    return
    0
    ;
    }
    Результат выполнения программы выше:
    15 20 25 8
    7 6
    С первыми двумя вызовами всё понятно.
    В третьем вызове, параметрами являются выражения, которые сначала нужно обработать. 2 + 3 = 5 и результат 5 присваивается переменной a. 4
    * 5 = 20 и результат 20 присваивается переменной b. Результатом выполнения функции add(5, 20) является значение 25.
    ravesli.com
    86
    Следующая пара относительно легкая: int x
    =
    4
    ;
    std
    ::
    cout
    <<
    add
    (
    x
    ,
    x
    )
    <<
    std
    ::
    endl
    ;
    // будет 4 + 4
    Здесь уже a = x и b = x. Поскольку x = 4, то add(x, x) = add(4, 4). Результат
    — 8.
    Теперь рассмотрим вызов посложнее: std
    ::
    cout
    <<
    add
    (
    1
    ,
    multiply
    (
    2
    ,
    3
    ))
    <<
    std
    ::
    endl
    ;
    // будет 1 + (2 * 3)
    При выполнении этого стейтмента процессор должен определить значения параметров a и b функции add(). З параметром a всё понятно — мы передаём значение 1 (a = 1). А вот чтобы определить значение параметра b, нам необходимо выполнить операцию умножения: multiply(2,
    3), результат — 6. Затем add(1, 6) возвращает число 7, которое и выводится на экран.
    Короче говоря: add(1, multiply(2, 3)) => add(1, 6) => 7
    Последний вызов может показаться немного сложным из-за того, что параметром функции add() является другой вызов add(): std
    ::
    cout
    <<
    add
    (
    1
    ,
    add
    (
    2
    ,
    3
    ))
    <<
    std
    ::
    endl
    ;
    // будет 1 + (2 + 3)
    Но здесь всё аналогично примеру выше. Перед тем как процессор вычислит внешний вызов функции add(), он должен обработать внутренний вызов функции add(2, 3). add(2, 3) = 5. Затем процессор обрабатывает функцию add(1, 5), результатом которой является значение
    6. Затем 6 передаётся в std::cout.
    Короче говоря: add(1, add(2, 3)) => add(1, 5) => 6
    ravesli.com
    87
    Тест
    1. Что не так со следующим фрагментом кода?
    #include void multiply
    (
    int a
    ,
    int b
    )
    {
    return a
    *
    b
    ;
    }
    int main
    ()
    {
    std
    ::
    cout
    <<
    multiply
    (
    7
    ,
    8
    )
    <<
    std
    ::
    endl
    ;
    return
    0
    ;
    }
    2. Какие здесь есть две проблемы?
    #include int multiply
    (
    int a
    ,
    int b
    )
    {
    int product
    =
    a
    *
    b
    ;
    }
    int main
    ()
    {
    std
    ::
    cout
    <<
    multiply
    (
    5
    )
    <<
    std
    ::
    endl
    ;
    return
    0
    ;
    }
    3. Какой результат выполнения следующей программы?
    #include int add
    (
    int a
    ,
    int b
    ,
    int c
    )
    {
    return a
    +
    b
    +
    c
    ;
    }
    int multiply
    (
    int a
    ,
    int b
    )
    {
    return a
    *
    b
    ;
    }
    int main
    ()
    {
    std
    ::
    cout
    <<
    multiply
    (
    add
    (
    3
    ,
    4
    ,
    5
    ),
    5
    )
    <<
    std
    ::
    endl
    ;
    return
    0
    ;
    }
    ravesli.com
    88 4. Напишите функцию doubleNumber(), которая принимает целое число в качестве параметра, умножает его на 2, а затем возвращает результат обратно в caller.
    5. Напишите полноценную программу, которая принимает целое число от пользователя (используйте cin), удваивает его с помощью функции doubleNumber() с предыдущего задания, а затем выводит результат на экран.
    ravesli.com
    89
    Урок №14. Почему функции полезны и как их эффективно
    использовать?
    Теперь, когда мы уже знаем, что такое функции и зачем они нужны, давайте более подробно рассмотрим то, почему они так полезны.
    Зачем использовать функции?
    Начинающие программисты часто спрашивают: «А можно ли обходиться без функций и весь код помещать непосредственно в функцию main()?".
    Если вашего кода всего 10-20 строчек, то можно, если же серьёзно, то функции предназначены для упрощения кода, а не для его усложнения.
    Они имеют ряд преимуществ, которые делают их чрезвычайно полезными в нетривиальных программах.

    Структура. Как только программы увеличиваются в размере/сложности, сохранять весь код внутри main() становится трудно. Функция - это как мини-программа, которую мы можем записать отдельно от головной программы, не заморачиваясь при этом об остальных частях кода. Это позволяет разбивать сложные задачи на более мелкие и простые, что кардинально снижает общую сложность программы.

    Повторное использование. После объявления функции, её можно вызывать много раз. Это позволяет избежать дублирования кода и сводит к минимуму вероятность возникновения ошибок при копировании/вставке кода. Функции также могут использоваться и в других программах, уменьшая объём кода, который нужно писать с нуля каждый раз.

    Тестирование. Поскольку функции убирают лишний код, то и тестировать его становится проще. А так как функция - это самостоятельная единица, то нам достаточно протестировать её один раз, чтобы убедиться в её работоспособности, а затем мы
    ravesli.com
    90 можем её повторно использовать много раз без необходимости проводить тестирование (до тех пор, пока не внесём изменения в эту функцию).

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

    Абстракция. Для того, чтобы использовать функцию, нам нужно знать её имя, данные ввода, данные вывода и где эта функция находится. Нам не нужно знать, как она работает. Это очень полезно для написания кода, понятного другим (например, стандартная библиотека С++ и всё, что в ней находится, создана по этому принципу).
    Каждый раз, при вызове std::cin или std::cout для ввода или вывода данных, мы используем функцию из стандартной библиотеки C++, которая соответствует всем указанным выше концепциям.
    Эффективное использование функций
    Одной из наиболее распространённых проблем, с которой сталкиваются новички, является понимание того, где, когда и как эффективно использовать функции. Вот несколько основных рекомендаций при написании функций:

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

    Код, который используется для сортировки чего-либо, лучше записать в виде отдельной функции. Например, если у нас есть список вещей, которые нужно отсортировать - пишем функцию
    ravesli.com
    91 сортировки, куда передаём несортированный список и откуда получаем отсортированный.

    Функция должна выполнять одно (и только одно) задание.

    Когда функция становится слишком большой, сложной или непонятной – её следует разбить на несколько подфункций. Это называется рефакторинг кода.
    При изучении C++ вам предстоит написать много программ, которые будут включать следующие три подзадания:

    Получение данных от пользователя.

    Обработка данных.

    Вывод результата.
    Для простых программ (менее, чем 30 строчек кода) частично или все из этих трёх подзаданий можно записать в функции main(). Для более сложных программ (или просто для практики) каждое из этих трёх подзаданий является хорошим вариантом для написания отдельной функции.
    Новички часто комбинируют обработку ввода и вывод результата в одну функцию. Тем не менее, это нарушает правило "одного задания".
    Функция, которая обрабатывает значение, должна возвращать его в caller, а дальше уже пускай caller сам решает, что ему с ним делать.
    ravesli.com
    92
    Урок №15. Локальная область видимости
    Как мы уже знаем из предыдущих уроков, при выполнении процессором стейтмента int х; создаётся переменная. Возникает вопрос: «Когда эта переменная уничтожается?".
    Область видимости переменной определяет, кто может видеть и использовать переменную во время её существования. И параметры функции, и переменные, которые объявлены внутри функции, имеют
    локальную область видимости. Другими словами, эти переменные используются только внутри функции, в которой они объявлены.
    Локальные переменные создаются в точке объявления и уничтожаются, когда выходят из области видимости.
    Рассмотрим следующую программу:
    #include int add
    (
    int a
    ,
    int b
    )
    // здесь создаются переменные a и b
    {
    // a и b можно видеть/использовать только внутри этой функции
    return a
    +
    b
    ;
    }
    // здесь a и b выходят из области видимости и уничтожаются
    int main
    ()
    {
    int x
    =
    7
    ;
    // здесь создаётся и инициализируется переменная x
    int y
    =
    8
    ;
    // здесь создаётся и инициализируется переменная y
    // x и y можно использовать только внутри функции main()
    std
    ::
    cout
    <<
    add
    (
    x
    ,
    y
    )
    <<
    std
    ::
    endl
    ;
    // вызов функции add() с a = x и b = y
    return
    0
    ;
    }
    // здесь x и y выходят из области видимости и уничтожаются
    Параметры a и b функции add() создаются при вызове этой функции, используются только внутри неё и уничтожаются при завершении выполнения этой функции.
    Переменные x и y функции main() можно использовать только внутри main() и они также уничтожаются при завершении выполнения функции main().
    ravesli.com
    93
    Для лучшего понимания разберём детальнее ход выполнения этой программы:

    выполнение начинается с функции main();

    создаётся переменная x функции main() и ей присваивается значение 7;

    создаётся переменная y функции main() и ей присваивается значение 8;

    вызывается функция аdd() с параметрами 7 и 8;

    создаётся переменная a функции add() и ей присваивается значение 7;

    создаётся переменная b функции add() и ей присваивается значение 8;

    выполняется операция сложения чисел 7 и 8, результатом чего является значение 15;

    функция add() возвращает значение 15 обратно в caller (в функцию main());

    переменные функции add() a и b уничтожаются;

    main() выводит значение 15 на экран;

    main() возвращает 0 в операционную систему;

    переменные функции main() x и y уничтожаются.
    Всё!
    Обратите внимание, если бы функция add() вызывалась дважды, параметры a и b создавались и уничтожались бы также дважды. В программе с большим количеством функций, переменные создаются и уничтожаются часто.
    ravesli.com
    94
    Локальная область видимости предотвращает возникновение
    конфликтов имён
    Из примера выше понятно, что переменные x и y отличаются от переменных a и b.
    Теперь давайте рассмотрим следующую программу:
    #include int add
    (
    int a
    ,
    int b
    )
    // здесь создаются переменные a и b функции add()
    {
    return a
    +
    b
    ;
    }
    // здесь a и b функции add() выходят из области видимости и уничтожаются
    int main
    ()
    {
    int a
    =
    7
    ;
    // здесь создаётся переменная a функции main()
    int b
    =
    8
    ;
    // здесь создаётся переменная b функции main()
    std
    ::
    cout
    <<
    add
    (
    a
    ,
    b
    )
    <<
    std
    ::
    endl
    ;
    // значения переменных a и b функции
    main() копируются в переменные a и b функции add()
    return
    0
    ;
    }
    // здесь a и b функции main() выходят из области видимости и уничтожаются
    Здесь мы изменили имена переменных x и y функции main() на a и b.
    Программа по-прежнему работает корректно, несмотря на то, что функция add() также имеет переменные a и b. Почему это не вызывает конфликт имён? Дело в том, что a и b функции main() являются локальными переменными, функция add() не может их видеть (и наоборот). Ни add(), ни main() не знают, что они имеют переменные с одинаковыми именами!
    Это значительно снижает возможность возникновения конфликта имён.
    Любая функция не должна знать или заботиться о том, какие переменные находятся в другой функции. Это также предотвращает возникновение ситуаций, когда одни функции могут непреднамеренно (или намеренно) изменять значения переменных других функций.
    Правило: Имена, которые используются внутри функции (включая
    параметры), доступны/видны только внутри этой же функции.
    ravesli.com
    95
    Тест
    Какой результат выполнения следующей программы?
    #include void doMath
    (
    int a
    )
    {
    int b
    =
    5
    ;
    std
    ::
    cout
    <<
    "doMath: a = "
    <<
    a
    <<
    " and b = "
    <<
    b
    <<
    std
    ::
    endl
    ;
    a
    =
    4
    ;
    std
    ::
    cout
    <<
    "doMath: a = "
    <<
    a
    <<
    " and b = "
    <<
    b
    <<
    std
    ::
    endl
    ;
    }
    int main
    ()
    {
    int a
    =
    6
    ;
    int b
    =
    7
    ;
    std
    ::
    cout
    <<
    "main: a = "
    <<
    a
    <<
    " and b = "
    <<
    b
    <<
    std
    ::
    endl
    ;
    doMath
    (
    a
    );
    std
    ::
    cout
    <<
    "main: a = "
    <<
    a
    <<
    " and b = "
    <<
    b
    <<
    std
    ::
    endl
    ;
    return
    0
    ;
    }
    1   2   3   4   5   6


    написать администратору сайта