Урок №48. Локальные переменные, область видимости и продолжительность жизни

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 77403

 ǀ   32 

Этот материал является продолжением урока №15.

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

Прежде чем мы начнем, нам нужно сначала разобраться с двумя терминами: область видимости и продолжительность жизни. Область видимости определяет, где можно использовать переменную. Продолжительность жизни (или «время жизни») определяет, где переменная создается и где уничтожается. Эти две концепции связаны между собой.

Переменные, определенные внутри блока, называются локальными переменными. Локальные переменные имеют автоматическую продолжительность жизни: они создаются (и инициализируются, если необходимо) в точке определения и уничтожаются при выходе из блока. Локальные переменные имеют локальную область видимости (или «блочную»), т.е. они входят в область видимости с точки объявления и выходят в самом конце блока, в котором определены.

Например, рассмотрим следующую программу:

Поскольку переменные x и y определены внутри блока, который является главной функцией, то они обе уничтожаются, когда main() завершает свое выполнение.

Переменные, определенные внутри вложенных блоков, уничтожаются, как только заканчивается вложенный блок:

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

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

Вложенные блоки считаются частью внешнего блока, в котором они определены. Следовательно, переменные, определенные во внешнем блоке, могут быть видны и внутри вложенного блока:

Сокрытие имен


Переменная внутри вложенного блока может иметь то же имя, что и переменная внутри внешнего блока. Когда подобное случается, то переменная во вложенном (внутреннем) блоке «скрывает» внешнюю переменную. Это называется сокрытием имен:

Результат выполнения программы:

10
5

Здесь мы сначала объявляем переменную oranges во внешнем блоке. Затем объявляем вторую переменную oranges, но уже во вложенном (внутреннем) блоке. Когда мы присваиваем oranges значение 10, то оно относится к переменной во вложенном блоке. После вывода этого значения (и окончания внутреннего блока), внутренняя переменная oranges уничтожается, оставляя внешнюю oranges с исходным значением (5), которое затем выводится. Результат выполнения программы был бы тот же, даже если бы мы назвали вложенную переменную по-другому (например, nbOranges).

Обратите внимание, если бы мы не определили вложенную переменную oranges, то идентификатор oranges относился бы к внешней переменной и значение 10 было бы присвоено внешней переменной:

Результат выполнения программы:

10
10

В обоих примерах на внешнюю переменную oranges никак не влияет то, что происходит с вложенной переменной oranges. Единственное различие между двумя программами — это то, к чему применяется выражение oranges = 10.

Сокрытие имен — это то, чего, как правило, следует избегать, поскольку оно может быть довольно запутанным!

Правило: Избегайте использования вложенных переменных с именами, идентичными именам внешних переменных.

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

Переменные должны определяться в максимально ограниченной области видимости. Например, если переменная используется только внутри вложенного блока, то она и должна быть определена в нем:

Ограничивая область видимости, мы уменьшаем сложность программы, поскольку число активных переменных уменьшается. Таким образом, легче увидеть, где какие переменные используются. Переменная, определенная внутри блока, может использоваться только внутри этого же блока (или вложенных в него подблоков). Этим мы упрощаем понимание и логику программы.

Если во внешнем блоке нужна переменная, то её необходимо объявлять во внешнем блоке:

Это один из тех редких случаев, когда вам может понадобиться объявить переменную до её первого использования.

Правило: Определяйте переменные в наиболее ограниченной области видимости.

Параметры функций


Хотя параметры функций не определяются внутри основного блока (тела) функции, в большинстве случаев они имеют локальную область видимости:

Заключение

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

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

Тест


Задание №1

Напишите программу, которая просит пользователя ввести два целых числа: второе должно быть больше первого. Если пользователь введет второе число меньше первого, то используйте блок и временную переменную, чтобы поменять местами пользовательские числа. Затем выведите значения этих переменных. Добавьте в свой код комментарии, объясняющие, где и какая переменная уничтожается.

Результат выполнения программы должен быть примерно следующим:

Введите число: 4
Введите большее число: 2
Меняем значения местами
Меньшее число: 2
Большее число: 4

Подсказка: Чтобы использовать кириллицу, добавьте следующую строчку кода в самое начало функции main():

Ответ №1

Задание №2

В чём разница между областью видимости и продолжительностью жизни переменной? Какую область видимости и продолжительность жизни по умолчанию имеют локальные переменные (и что это значит)?

Ответ №2

Область видимости определяет, где переменная доступна для использования. Продолжительность жизни переменной определяет, когда переменная создается и когда уничтожается.

Локальные переменные имеют локальную (блочную) область видимости, доступ к ним осуществляется только внутри блока, в котором они определены.

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

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (475 оценок, среднее: 4,94 из 5)
Загрузка...

Комментариев: 32

  1. Влад:

    Не  понял как добавить временную переменную, поєтому упростил

  2. Сашуня:

    Задание:

  3. ОЛЕГ-777:

    Конечно это не по теме урока, но просто тянется рука использовать условный тернарный оператор, который мы уже прошли в уроке 41. Короткий вариант программы:

    main.ccp:

    1. Дмитрий Соколов:

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

  4. skillpa11:

    Добрый день!
    В уроке 12
    https://ravesli.com/urok-12-funktsii-i-return/#toc-4
    указано —
    "процессор встречает в функции оператор return, он немедленно выполняет возврат значения обратно в caller и точка выполнения также переходит в caller. Любой код, который находится за return-ом в функции — игнорируется."
    В ответе №1 на Задание №1 Вы указали в комментарии

    , что временные переменные уничтожаются ЗА ОПЕРАТОРОМ return
    Вопрос- действительно ли это так? ведь за return уже ничего нет…
    Т.е. уничтожение ДОЛЖНО произойти в момент return
    В источнике https://docs.microsoft.com/ru-ru/cpp/cpp/functions-cpp?view=msvc-160
    "Переменные, объявленные в теле функции, называются локальными. Они исчезают из области видимости при выходе из функции, поэтому функция никогда не должна возвращать ссылку на локальную переменную."

    Есть также интересный эксперимент — с уничтожением временных объектов.

    https://ru.stackoverflow.com/questions/430567/%D0%9F%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA-%D1%83%D0%BD%D0%B8%D1%87%D1%82%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2

    1. Богдан:

      Вот по этому и стоит учить ассемблер. Для понимания, что, как и когда делается. На самом деле ничего не уничтожается.

      1. Сергей:

        Молодец, Богдан. "На самом деле ничего не уничтожается."
        При объявлении переменной в функции часть оперативной памяти выделяется под этот объект (урок 10) https://ravesli.com/urok-10-peremennye-initsializatsiya-i-prisvaivanie-v-s/
        После возвращения из функции область памяти, где хранились переменные помечается 'как свободная' (для программистов там мусор). Значения в этой области или от прежних событий (т. е. ваши бывшие локальные переменный ), или перезаписаны сервисами операционной системы.
        В любом случае доступ к этой области памяти через "псевдоимя" типа x или подобное ("объект с именем") — не доступен.

  5. Сосед:

    Блин, ни как не получается перевести иероглифы в кирилицу, я пробовал:
    ———————-

    ———————-

    ———————-
    Может кто сталкивался, че подскажите?
    компилирую через g++

    1. Viktor:

      Инклуде виндовх пишешь в самом верху.
      Сет консоле сп 1251 пишешь сразу после инт мэйн в теле.
      Так же файл блокнота тоде должен быть в кодировке 1251

    2. Иван:

      В самом начале функции main нужно написать setlocale (LC_ALL, "Russian") и по идее всегда будет работать.

  6. AHTOH:

    Интересно, а к каких нибудь компиляторах существует функция размена?
    К примеру если мне нужно разменять переменные по идее достаточно изменить им выделенные адреса памяти (кстати тоже разменять).
    Я вот не помню точно, в ассемблере вроде так можно было одной командой.

  7. Виктор:

    1. Максим:

      В задаче требуется использовать только 1 доп переменную

  8. Александр:

  9. Денис:

    Думаю, так даже проще должно быть

  10. Sagynysh:

  11. Alex:

  12. Павел Карпов:

  13. Inviser666:

  14. armus1:

  15. Елена:

    Еще вариант:

  16. Дмитрий:

  17. Игорь:

  18. Максим:

  19. Георгий:

    хм, сделал немного наоборот, но вроде смысл тот же

  20. master114:

    У меня получился такой вариант — ibb.co/jJLATc. Сделал пару функций. Перед выполнением думал, что получится поменять без временной переменной (в моем случае Z).

    1. Фото аватара Юрий:

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

      1. master114:

        Нашел вариант без временной переменной — onlinegdb.com/B1E-4RKpM.

        1. Фото аватара Юрий:

          Хоть и работает, но у вас здесь вместо одной временной переменной используются две временные переменные: xFunc и yFunc. + еще глобальные переменные, которые нежелательно лишний раз использовать.

          Но в общем, реализация интересная однозначно.

      2. Mirovengil:

        В каком смысле "без дополнительной переменной не обойтись"? А как же классика?

        PS: имена переменным поставил простейшие, чтобы было понятно, что происходит.

  21. Sergey Groysman:

    Юрий, доброго дня.
    При решении теста №1, как сюда ввести вариант, если ввели равные числа?
    Спасибо.

    1. Фото аватара Юрий:

      Если ввести правильные числа сразу, то они и выведутся после, без выполнения условия if. Дополнительно ничего прописывать не нужно. В условии if ведь и указывается, что менять значение нужно только при условии что значение smaller, которое ввел пользователь — больше значения large. Если же это не так, то ничего менять и не нужно.

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *