Функции и процедуры. Рекурсия
Внутри функции могут быть объявлены переменные, как, например, переменные p и i в функции power . Такие переменные называются и они определены только внутри этой функции. Переменные, определенные вне тела любой функции (ранее мы такие переменные вообще не рассматривали) называются и они определены всюду начиная с места определения и до конца файла. Глобальными переменными можно пользоваться во всех функциях, но с современной точки зрения использовать глобальные переменные рекомендуется как можно реже.
Локальные переменные создаются каждый раз при входе в функцию и уничтожаются при выходе из нее. Таким образом, значения, сохраненные в локальных переменных, пропадут после завершения работы функции.
В различных функциях можно определять переменные с одним и тем же именем. Это будут различные переменные. Также можно объявлять в функциях переменные, имена которых совпадают с именами глобальных переменных. Тогда будет создана новая локальная переменная, а изменить значение глобальной переменной с таким именем будет невозможно. Пример:
#include
using namespace std;
int i; // i - глобальная переменная
void f1() int i; // Определена локальная переменная i
i=5; // Изменяется значение локальной переменной
cout >
void f2() i=3; // Изменяется значение глобальной переменной
>
int main() i=1; // Изменяется значение глобальной переменной
f1(); // f1() не меняет значение глобальной переменной
cout f2(); // f2() меняет значение глобальной переменной
cout return 0; >
Вопрос: как будет работать программа, если добавить в функцию main определение переменной i , как локальной? А если при этом убрать объявление глобальной переменной i?
Передача параметров по значению и по ссылке
Переменные, в которых сохраняются параметры, передаваемые функции, также являются локальными для этой функции. Эти переменные создаются при вызове функции и в них копируются значения, передаваемые функции в качестве параметров. Эти переменные можно изменять, но все изменения этих переменных будут «забыты» после выхода из функции. Рассмотрим это на примере следующей функции, «меняющей» значения двух переданных ей переменных:
#include
using namespace std;
void swap(int a, int b)
int t;
t=b;
b=a;
a=t;
>
int main()
int p=3,q=5;
swap(p,q);
cout return 0;
>
При вызове функции swap создаются новые переменные a и b , им присваиваются значения 3 и 5. Эти переменные никак не связаны с переменными p и q и их изменение не изменяет значения p и q . Такой способ передачи параметров называется .
Чтобы функция могла изменять значения переменных, объявленных в других функциях, необходимо указать, что передаваемый параметр является не просто константной величиной, а переменной, необходимо передавать значения . Для этого функцию swap следовало бы объявить следующим образом:
void swap(int & a, int & b)
Амперсанды перед именем переменной означают, что эта переменная является не локальной переменной, а ссылкой на переменную, указанную в качестве параметра при вызове функции. Теперь при вызове swap(p,q) переменные a и b являются синонимами для переменных p и q , и изменение их значений влечет изменение значений p и q . А вот вызывать функцию в виде swap(3,5) уже нельзя, поскольку 3 и 5 — это константы, и сделать переменные синонимами констант нельзя.
Однако в языке C (не C++) вообще не было такого понятия, как передача параметров по ссылке. Для того, чтобы реализовать функцию, аналогичную swap в рассмотренном примере, необходимо было передавать адреса переменных p и q , а сама функция при этом должна быть объявлена, как
void swap(int * a, int * b)
Поскольку в этом случае функция swap знает физические адреса в оперативной памяти переменных p и q , то разыменовав эти адреса функция swap сможет изменить значения самих переменных p и q .
Теперь вспомним, что в C++ массивы и указатели — это почти одно и то же. А поскольку передача массива по значению, то есть создание копии всего массива является трудоемкой операцией (особенно для больших массивов), то вместо массива всегда передается указатель на его начало. То есть два объявления функции void f(int A[10]) и void f(int * A) абсолютно идентичны. В любом случае функция f получит указатель на начало массива, а, значит, будет способна изменять значения его элементов.
Упражнения
Функции — удобный способ структурирования программы. Существует мнение, что если фрагмент программы реализует некоторую законченную алгоритмическую идею и состоит более чем из 10 строк, то его обязательно надо оформить в виде отдельной функции.
Упражнения к этому листку объединены темой генерирования комбинаторных объектов (перестановок, подмножеств и т.д.) Такие объекты следует хранить в массивах, например, перестановка чисел от 1 до n — это массив типа int[n] , заполненный числами от 1 до n .
В программе должны быть следующие функции ( p — массив для хранения комбинаторного объекта, n — число элементов в нем):
int * Init (int n); // Создание и инициализация массива
bool Next (int * p, int n); // Построение следующего комбинаторного объекта
void Print(int * p, int n); // Печать комбинаторного объекта
void Done (int * p); // Освобождение памяти
а функция main должна иметь следующую структуру:
cin>>n;
p=Init(n);
Print(p,n);
while( Next(p,n) )
Print(p,n);
Done(p);
Кроме того, программа должны работать за оптимальное время.
- По данным числам n и k выведите на экран все строки длины n, состоящие из чисел 1, . k в лексикографическом (алфавитном) порядке.
- По данному n выведите на экран все подмножества множества .
- По данным n и k выведите на экран все двоичные строки длины n, содержащие ровно k единиц в лексикографическом порядке.
- По данному n напечатайте все перестановки чисел от 1 до n в лексикографическом порядке.
- По данному n напечатайте все способы размещения из n элементов k элементов (количество способов выбрать из чисел от 1 до n ровно k чисел с учетом порядка выбора).
- По данному числу n напечатайте всевозможные его представления в виде суммы натуральных слагаемых. Представления, различающиеся порядком слагаемых, считать за одно.
- По данному слову (или последовательности цифр) напечатайте всевозможные перестановки его букв. Учтите, что буквы исходного слова могут совпадать.
Руководство по глобальным переменным
Переменная, доступ к которой можно получить из любого места в коде, называется глобальной. Ее можно определить вне блока. Другими словами, глобальная переменная, объявленная вне функции, будет доступна внутри нее.
С другой стороны, переменная, объявленная внутри определенного блока кода, будет видна только внутри этого же блока — она называется локальной.
Разберемся с этими понятиями на примере.
Пример локальных и глобальных переменных
def sum(): a = 10 # локальные переменные b = 20 c = a + b print("Сумма:", c) sum()Переменная объявлена внутри функции и может использоваться только в ней. Получить доступ к этой локальной функции в других нельзя.
Для решения этой проблемы используются глобальные переменные.
Теперь взгляните на этот пример с глобальными переменными:
a = 20 # определены вне функции b = 10 def sum(): c = a + b # Использование глобальных переменных print("Сумма:", c) def sub(): d = a - b # Использование глобальных переменных print("Разница:", d) sum() sub()Сумма: 30 Разница: 10В этом коде были объявлены две глобальные переменные: a и b . Они используются внутри функций sum() и sub() . Обе возвращают результат при вызове.
Если определить локальную переменную с тем же именем, то приоритет будет у нее. Посмотрите, как в функции msg это реализовано.
def msg(): m = "Привет, как дела?" print(m) msg() m = "Отлично!" # глобальная переменная print(m)Привет, как дела? Отлично!Здесь была объявлена локальная переменная с таким же именем, как и у глобальной. Сперва выводится значение локальной, а после этого — глобальной.
Ключевое слово global
Python предлагает ключевое слово global , которое используется для изменения значения глобальной переменной в функции. Оно нужно для изменения значения. Вот некоторые правила по работе с глобальными переменными.
Правила использования global
- Если значение определено на выходе функции, то оно автоматически станет глобальной переменной.
- Ключевое слово global используется для объявления глобальной переменной внутри функции.
- Нет необходимости использовать global для объявления глобальной переменной вне функции.
- Переменные, на которые есть ссылка внутри функции, неявно являются глобальными.
Пример без использования глобального ключевого слова.
c = 10 def mul(): c = c * 10 print(c) mul()line 5, in mul c = c * 10 UnboundLocalError: local variable 'c' referenced before assignmentЭтот код вернул ошибку, потому что была предпринята попытка присвоить значение глобальной переменной. Изменять значение можно только с помощью ключевого слова global .
c = 10 def mul(): global c c = c * 10 print("Значение в функции:", c) mul() print("Значение вне функции:", c)Значение в функции: 100 Значение вне функции: 100Здесь переменная c была объявлена в функции mul() с помощью ключевого слова global . Ее значение умножается на 10 и становится равным 100. В процессе работы программы можно увидеть, что изменение значения внутри функции отражается на глобальном значении переменной.
Глобальные переменные в модулях Python
Преимущество использования ключевого слова global — в возможности создавать глобальные переменные и передавать их между модулями. Например, можно создать name.py, который бы состоял из глобальных переменных. Если их изменить, то изменения повлияют на все места, где эти переменные встречаются.
1. Создаем файл name.py для хранения глобальных переменных:
Область видимости переменных в C++: локальные и глобальные переменные
Всем привет! Сегодня мы затронем тему, которую должны были изучить еще в самом начале пути изучения C++ - область видимости переменных. Мы разберем, что такое локальные и глобальные переменные.
Область видимости переменных в C++
Область видимости переменных - это те части программы, в которой пользователь может изменять или использовать переменные в своих нуждах.
В C++ существуют отдельные блоки, которые начинаются с открывающей скобки ( < ) и заканчиваются соответственно закрывающей скобкой ( >). Такими блоками являются циклы (for, while, do while) и функции.
int func () // блок (функция - func) > int main() // блок (функция - main) for (int i = 0; i 10; i++) // блок (цикл - for), также является дочерним блоком функции main for (int j = 0; j 5; j++) // блок (цикл - for), но он еще является и дочерним блоком для первого цикла > > system("pause"); return 0; >Если переменная была создана в таком блоке, то ее областью видимости будет являться этот блок от его начала (от открывающей скобки - < ) и до его конца (до закрывающей скобки - >) включая все дочерние блоки созданные в этом блоке.
В примере ниже, программист ошибся с областью видимости:
- Он создал переменную j во втором цикле.
- Использовав ее в первом цикле for он вынудил компилятор сообщить об ошибке (переменной j больше нет, поскольку второй цикл закончил свою работу).
int main() for (int i = 0; i 10; i++) int b = i; for (int j = 0; j 5; j++) cout + j; > cout ; // ошибка: так как переменная j была создана в другом блоке > system("pause"); return 0; >
А вот ошибки в строке 6 нет, поскольку второй цикл находится в первом цикле (является дочерним блоком первого цикла) и поэтому переменная b может спокойно там использоваться.
Глобальные переменные в C++
Глобальными переменными называются те переменные, которые были созданы вне тела какого-то блока. Их можно всегда использовать во всей вашей программе, вплоть до ее окончания работы. В примере ниже мы создали две глобальные переменные global и global_too и использовали их в функции summa :
int global = 5; // глобальные int global_too = 10; // переменные int summa() cout + global_too; // суммируем числа > int main() summa(); // вызываем функцию summa system("pause"); return 0; >
Вот, что выведет данная программа:
15 Process returned 0 (0x0) execution time : 0.010 s Press any key to continue.
Как видите глобальные переменные видны везде. В нашем примере внутри функции summa мы не создавали ни какие переменные, мы лишь использовали две глобальные переменные, которые были созданы раньше.
Локальные переменные - это переменные созданные в блоках. Областью видимости таких переменных является блоки ( и все их дочерние ), а также их область видимости не распространяется на другие блоки. Как ни как, но эти переменные созданы в отдельных блоках.
Из этого можно сделать вывод: у нас есть возможность создавать переменные с одинаковыми именами, но в разных блоках (или другими словами, чтобы их область видимости не совпадала друг с другом).
int main() for (int i = 0; i 2; i++) int b = i; // локальная переменная (она находится в блоке for) cout ; > system("pause"); return 0; >
В примере выше блоком где была создана локальная переменная b является цикл for (2 - 5). А вот если бы мы захотели вывести переменную b вне блока for , компилятор сообщил бы нам об ошибке, подробнее об этом говорится ниже.
Распространенной ошибкой среди начинающих программистов является использование локальных переменных в других блоках. Например ниже мы решили использовать переменную cost в функции summa , хотя мы ее создали в совершенно другой функции - main .
int summa () cout ; // ошибка > int main() int cost = 10; // переменная созданная в блоке main summa(); system("pause"); return 0; >
Нужно запомнить! Если вы создали локальную переменную, то вы должны понимать, что использование ее в других блоках будет невозможным.
Глобальная переменная уступает локальной
Если мы создадим глобальную переменную и с таким же именем локальную, то получится, что там где была создана локальная переменная будет использоваться именно локальная переменная, а не глобальная. Так как локальная переменная считается по приоритету выше глобальной. Давайте разберем, как это работает на примере ниже:
string str = "You lucky!"; void message() string str = "You very lucky man!"; cout ; > void sait_message() cout ; >
Мы создали глобальную переменную str со значением “You lucky!” и локальную переменную с таким же названием в функции message , но с другим значением - “You very lucky man!“. Если мы вызовем функцию message , то результатом будет:
You very lucky man! Process returned 0 (0x0) execution time : 0.010 s Press any key to continue.
А вот, если мы вызовем функцию sait_message то результатом будет:
You lucky! Process returned 0 (0x0) execution time : 0.010 s Press any key to continue.
Вот так глобальная переменная уступает локальной!
Мы советуем вам не создавать переменные с одинаковыми именами, поскольку в будущем вам будет тяжело разобраться в коде, если там будут присутствовать одинаковые переменные.
Глобальный оператор разрешения
В случае создания двух переменных с одинаковым именем (одна из которых является глобальной, а другая локальной) при использовании в блоке, в котором была объявлена локальная переменная, можно использовать и глобальную переменную. Для ее использования нужно всего лишь применить глобальный оператор разрешения.
Глобальный оператор разрешения - это два подряд поставленные двоеточия, с помощью которых мы говорим компилятору, что хотим использовать глобальную переменную, а не локальную.
Чтобы использовать глобальный оператор разрешения нужно применять данную конструкцию:
:: имя глобальной переменной>
В примере ниже вы можете увидеть, как работает глобальный оператор разрешения:
string str = "You lucky!"; void message() string str = "You very lucky man!"; cout <:: str; // использовали глобальный оператор разрешения >
Получится вот такой результат, если мы вызовем функцию message :
You lucky! Process returned 0 (0x0) execution time : 0.010 s Press any key to continue.
Какие виды переменных использовать
Сегодня мы разобрали, что такое область видимости в C++. Также мы рассмотрели, что такое локальные переменные и глобальные переменные.
У многих может возникнуть соответствующий вопрос:“Какие переменные нам лучше использовать в своих программах?“. Мы считаем, что разницы нет, какие переменные вы будете использовать, глобальные и локальные виды переменных нужно использовать вместе. Тяжело будет использовать только один вид переменных!
Мы рады, если вам понравилась данный урок. Если вы хотите оставить свой вопрос, то пишите его в комментариях. Нам будет приятно, если вы поделитесь данной статьей со своими друзьями. Удачи!
Читайте также
Цикл do while в C++
В очередном уроке по C++ мы пройдем цикл do while. В этом уроке вы узнаете как его просто реализовать и закрепим пройденные знания на примере. Удачи!
Динамические массивы и переменные в C++
Как пользоваться динамическими переменными и массивами в C++. Мы разберем как их создать и узнаем их плюсы перед использованием обычных массивов.
Инкремент и декремент в C++
Инкременты и декременты позволяют увеличивать и уменьшать значения переменных на единицу. Также мы научимся использовать постфиксные и префиксные операторы.
Мы рассмотрим создание программы, ее структуру, а также главные правила синтаксиса язык
