Как объявить глобальную переменную с
Все переменные имеют определенное время жизни (lifetime) и область видимости (scope). Время жизни начинается с момента определения переменной и длится до ее уничтожения. Область видимости представляет часть программы, в пределах которой можно использовать объект. Как правило, область видимости ограничивается блоком кода, который заключается в фигурные скобки. В зависимости от области видимости создаваемые объекты могут быть глобальными, локальными или автоматическими.
Глобальные объекты
Глобальные переменные определены в файле программы вне любой из функций или любого другого блока кода и могут использоваться любой функцией. Глобальные переменные существуют в течение всей жизни программы и уничтожаются лишь с завершением программы.
Если глобальные переменные не инициализированы, то они получают нулевые значения.
Например, определим и используем глобальную переменную:
#include int n; // глобальная переменная void print() < n++; std::cout int main() < print(); // n=6 n++; std::cout локальными. Такие объекты доступны в пределах только того блока кода, в котором они определены.Автоматические объекты
Локальные объекты, которые существуют только во время выполнения того блока, в котором они определены, являются автоматическими.
При входе в блок для подобных переменных выделяется память, а после завершения работы этого блока, выделенная память освобождается, а объекты удаляются.
#include void print() < int n ; // локальная переменная, которая существует только в функции print std::cout int main() < int m ; // локальная переменная, которая существует только в функции main std::cout #include int main() < int n1 ; // область видимости - вся функция main < int n2 ; // область видимости - блок кода std::cout // конец блока функции - конец времени жизни переменной n2 // так нельзя - переменная n2 из блока функции уже не существует // std::cout #include int n ; int main() < int n ; std::cout ; std::cout n. Переменная n, определенная на уровне функции main (int n = 10;) скрывает глобальную переменную n. А переменная n, определенная на уровне блока, скрывает переменную, определенную на уровне функции main.Однако иногда бывает необходимо обратиться к глобальной переменной. В этом случае для обращения именно к глобальной переменной можно использовать оператор :: перед именем переменной
#include int n ; int main() < int n ; std::cout ; std::cout static. Если автоматические переменные определяются и инициализируются при каждом входе в функцию, то статические переменные инициализируются только один раз, а при последующих вызовах функции используется старое значение статической переменной. То есть разница между локальными автоматическими и локальными статическими переменными состоит во времени жизни: автоматические переменные существуют до конца выполнения блока кода, а статические - до конца выполнения программы.Например, пусть у нас будет функция со стандартной автоматической переменной:
#include void print() < int n ; std::coutn=1 n=1 n=1Теперь сделаем переменную n статической:
#include void print() < static int n ; std::coutn=1 n=2 n=3Локальные и глобальные переменные в С++
Каждая переменная имеет свою область видимости, то есть такую область, в которой можно работать с переменной. За пределами этой области, о данной переменной ничего известно не будет, а значит и использовать её нельзя. Итак, переменная находится в области видимости, если к ней можно получить доступ.
Существуют локальные и глобальные переменные. Так вот, переменные, объявленные внутри функции, называются локальными. Локальные переменные имеют свои области видимости, этими областями являются функции, в которых объявлены переменные. Таким образом, в разных функциях можно использовать переменные с одинаковыми именами, что в свою очередь очень удобно. Разделение переменных на глобальные и локальные соответствует одному из главных правил программирования, а именно – принципу наименьших привилегий. То есть, переменные, объявленные внутри одной функции, должны быть доступны только для этой функции и ни чему другому, в конце концов, они создавались именно для этой функции. Глобальные переменные объявляются вне тела какой-либо функции, и поэтому область видимости таких переменных распространяется на всю программу. Обычно глобальные переменные объявляются перед главной функцией, но можно объявлять и после функции main() , но тогда данная переменная не будет доступна в функции main() .
Разработаем программу, в которой будут объявлены две переменные, локальная и глобальная, с одинаковым именем.
// variables.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < cout// variables.cpp: определяет точку входа для консольного приложения. #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < coutВ строках 8 и 12 объявлены переменные одинакового типа с одним и тем же именем variable , но переменная в строке 8 является глобальной переменной, а переменная в строке 12 — это локальная переменная. Функция example() имеет доступ только к глобальной переменной. В то время как функция main() имеет доступ как к локальной так и к глобальной переменным. Если в области видимости есть и локальная и глобальная переменные с одинаковыми именами, то при обращении к ним, будет использоваться ближайшая переменная, а это локальная переменная, это видно по результату работы программы (см. Рисунок 1).
CppStudio.com
local variable = 12 global variable = 48Рисунок 1 — Локальные и глобальные переменные в С++
Как мы уже сказали, функция main() имеет доступ и к глобальной переменной, но не показали, как получить этот доступ. В С++ существует такая операция, как разрешение области действия :: . Эта операция позволяет обращаться к глобальной переменной из любого места программы.» Все, что нужно сделать, так это поставить двойное двоеточие перед именем переменной. Ниже показан код, верхней программы с одним лишь изменением, и это изменение – операция разрешения доступа в строке 13.
// variables.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < cout// variables.cpp: определяет точку входа для консольного приложения. #include using namespace std; void example(); int variable = 48; // инициализация глобальной переменной int main(int argc, char* argv[]) < int variable = 12; // инициализация локально переменной cout void example() < coutОперация разрешения области действия ставится перед именем глобальной переменной, и даже, если есть локальная переменная с таким же именем, программа будет работать со значением, содержащимся в глобальной переменной. Результат работы программы (см. Рисунок 2).
CppStudio.com
local variable = 48 global variable = 48Рисунок 2 — Локальные и глобальные переменные в С++
К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!
Глобальные переменные
В противоположность локальным переменным глобальные переменные видны всей программе и могут использоваться любым участком кода. Они хранят свои значения на протяжении всей работы программы. Глобальные переменные создаются путем объявления вне функции. К ним можно получить доступ в любом выражении, независимо от того, в какой функции находится данное выражение.
В следующей программе можно увидеть, что переменная count объявлена вне функций. Она объявляется перед функцией main(). Тем не менее, она может быть помещена в любое место до первого использования, но не внутри функции. Общепринятым является объявление глобальных переменных в начале программы.
void func1(void) , func2(void);
int count; /* count является глобальной переменной */
int main(void)
count = 100;
func1 ();
return 0; /* сообщение об удачном завершении работы */
>void func1 (void)
func2 ();
printf("счетчик %d", count); /* выведет 100 */
>Рассмотрим поближе данный фрагмент программы. Следует понимать, что хотя ни main(), ни func1() не объявляют переменную count, но они оба могут ее использовать. func2() объявляет локальную переменную count. Когда func2() обращается к count, она обращается только к локальной переменной, а не к глобальной. Надо помнить, что если глобальная и локальная переменные имеют одно и то же имя, все ссылки на имя внутри функции, где объявлена локальная переменная, будут относиться к локальной переменной и не будут иметь никакого влияния на глобальную,. это очень удобно. Если забыть об этом, то может показаться, что программа работает странно, даже если все выглядит корректно.
Глобальные переменные хранятся в фиксированной области памяти, устанавливаемой компилятором. Глобальные переменные чрезвычайно полезны, когда одни и те же данные используются в нескольких функциях программы. Следует избегать ненужного использования глобальных переменных по трем причинам:
- Они используют память в течение всего времени работы программы, а не тогда, когда они необходимы.
- Использование глобальных переменных вместо локальных приводит к тому, что функции становятся более частными, поскольку они зависят от переменных, определяемых снаружи.
- Использование большого числа глобальных переменных может вызвать ошибки в программе из-за неизвестных и нежелательных эффектов.
Одним из краеугольных камней структурных языков является разделение кода и данных. В С разделение достигается благодаря использованию локальных переменных и функций. Например, ниже показаны два способа написания mul() — простой функции, вычисляющей произведение двух целых чисел.
| Общий | Частный |
|---|---|
| int mul(int х, int у) return(x*y); > |
int х, у; int mui(void) return(x*y); > |
Обе функции возвращают произведение переменных х и у. Тем не менее общая или параметризированная версия может использоваться для вычисления произведения любых двух чисел, в то время как частная версия может использоваться для вычисления произведения только глобальных переменных х и у.
Функции и процедуры. Рекурсия
В предыдущем листке была задача вычисления числа сочетаний из n элементов по k, для чего необходимо вычисление факториалов трех величин: n, k и n-k. Для этого можно сделать три цикла, что приводит к увеличению размера программы за счет трехкратного повторения похожего кода. Вместо этого лучше сделать одну , вычисляющую факториал любого данного числа n и трижды использовать эту функцию в своей программе. Соответствующая функция может выглядеть так:
Этот текст должен идти до основной программы, то есть до функции main() . Первая строчка этого примера является описанием нашей функции. factorial – идентификатор, то есть имя нашей функции. После идентификатора в круглых скобках идет список параметров, которые получает наша функция. Список состоит из перечисленных через запятую типов параметров и их идентификаторов. В нашем случае список состоит из одной величины n , имеющей тип int : наша функция вычисляет факториал целого числа. Функция вычисляет целочисленную величину, поэтому функция будет возвращать значение типа int , что указывается до идентификатора функции. Функция может не возвращать никакого значения, тогда в качестве типа возвращаемого значения должно быть указано слово void .
Далее идет тело функции в фигурных скобках. Внутри функции вычисляется значение факториала числа n и оно сохраняется в переменной f . Функция завершается инструкцией return f , которая завершает работу функции и возвращает значение переменной f . Инструкция return может встречаться в произвольном месте функции, ее исполнение завершает работу функции и возвращает указанное значение в место вызова. Если функция не возвращает значения, то инструкция return используется без возвращаемого значения, также в функциях, не возвращающих значения, инструкция return может отсутствовать.
Функция должна быть описана до начала основной программы. Сама же основная программа, как можно догадаться, также является функцией с именем main , не получающая никаких параметров и возвращающее значение типа int .
Теперь мы можем использовать нашу функцию factorial в основной программе нахождения числа сочетаний:
В этом примере мы трижды вызываем функцию factorial для вычисления трех факториалов: factorial(n) , factorial(k) , factorial(n-k) .
Мы также можем объявить функцию binomial , которая принимает два целочисленных параметра n и k и вычисляет число сочетаний из n по k :
int binomial (int n, int k)
return factorial(n)/(factorial(k)*factorial(n-k));
>
Тогда в нашей основной программе мы можем вызвать функцию binomial для нахождения числа сочетаний:
Поскольку в этом случае функция main вызывает функцию binomial , а функция binomial вызывает функцию factorial , а каждая функция должна быть описана до ее вызова из другой функции, то порядок описания функций в программе должен быть такой:
int factorial (int n)
int binomial (int n, int k)
Вернемся к задаче нахождения наибольшего из двух или трех чисел. Напишем функцию, находящую максимум из двух данных чисел:
double max (double a, double b)
if (a>b)
return a;
else
return b;
>
Теперь мы можем реализовать функцию max , находящую максимум трех чисел:
double max (double a, double b, double c)
return max( max(a,b), c);
>
В данном примере написаны две различные функции max : первая с двумя параметрами, вторая с тремя параметрами. Несмотря на то, что функции имеют одинаковые имена, по количеству передаваемых параметров ясно, какая из них имеется в виду. В нашем случае функция max (double a, double b, double c) дважды вызывает функцию max для двух чисел: сначала, чтобы найти максимум из a и b , потом чтобы найти максимум из этой величины и c .
Упражнения
- (A) Напишите функцию int min (int a, int b, int c, int d) , находящее наименьшее из четырех данных чисел. Функция main дожна считывать четыре числа с клавиатуры, вызывать функцию min , выводить результат ее работы на экран.
- (B) Напишите функцию double power (double a, int n) , вычисляющую значение a n . Функция main должна считывать числа a и n , вызывать функцию power , выводить результат ее работы на экран.
- (C) Напишите функцию bool Xor (bool x, bool y) , реализующую функцию "Исключающее ИЛИ" двух логических переменных x и y. Функция Xor должна возвращать true , если ровно один из ее аргументов x или y , но не оба одновременно равны true . Функция main в программе должна запрашивать значения переменных x и y , (два числа, равных 0 или 1), вызывать функцию Xor(x,y) и выводить результат на экран.
- (D) Напишите "функцию голосования" bool Election(bool x, bool y, bool z) , которая возвращает то значение ( true или false ), которое среди значений ее аргументов x , y , z встречается чаще. Функция main должна запрашивать три числа, равных 0 или 1, вызывать функцию Election и выводить результат на экран.
- (E) Напишите функцию bool IsPrime (int n) , возвращающую true , если натуральное число n>1 простое, и false , если составное. Функция main должна запрашивать число с клавиатуры, вызывать функцию IsPime , выводить строку prime , если число простое или composite , если число составное. Указание: число является составным, если оно имеет натуральный делитель, отличный от 1 до n. Программа должна проверить делимость числа n на все числа от 2 до n-1 и вернуть false при нахождении нетривиального делителя. Для того, чтобы проверить, что число n делится на число d нацело, необходимо сравнить остаток от деления n на d с нулем.
Рекурсия
- Неправильное оформление выхода из рекурсии. Например, если мы в программе вычисления факториала забудем поставить проверку if (n==0) , то factorial(0) вызовет factorial(-1) , тот вызовет factorial(-2) и т.д.
- Рекурсивный вызов с неправильными параметрами. Например, если функция factorial(n) будет вызывать factorial(n) , то также получиться бесконечная цепочка.
Упражнения
- (B) Напишите рекурсивную функцию возведения в степень, пользующуюся следующим свойством: a n =a*a n-1 .
- (F) Напишите функцию возведения в степень, которая работала бы как для положительных, так и для отрицательных значений n: a -n =1/a n .
- (G) Напишите функцию быстрого возведения в степень, которая пользовалась бы следующими свойствами: a n =(a n/2 ) 2 при четном n, a n =a*a n-1 при нечетном n. Подумайте, сколько умножений выполнит эта функция для вычисления a n ?
- (H) Последовательность Фибоначчи определена следующим образом: φ0=1, φ1=1, φn=φn-1+φn-2 при n>1. Начало ряда Фибоначчи выглядит следующим образом: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, . Напишите функцию int phi(int n) , которая по данному натуральному n возвращает φn. Функция n должна считывать значение n и выводить значение n-го числа Фибоначчи.
- (I) Для биномиальных коэффициентов (числа сочетаний из n по k) хорошо известна рекуррентная формула: Cn k =Cn-1 k-1 +Cn-1 k . Вычислите значение Cn k , пользуясь этой формулой и учитывая, что Cn 0 =Cn n =1.
- (J) Головоломка "Ханойские башни" состоит из трех колышков, пронумерованных числами 1, 2, 3. На колышек 1 надета пирамидка из n дисков различного диаметра в порядке возрастания диаметра. Диски можно перекладывать с одного колышка на другой по одному, при этом диск нельзя класть на диск меньшего диаметра. Необходимо переложить всю пирамидку с колышка 1 на колышек 2 за минимальное число перекладываний. Напишите программу, которая решает головоломку – для данного числа дисков n печатает последовательность перекладываний в формате "Disk 1 move from 1 to 2" (диск 1 переложить c колышка 1 на колышек 2), печатая по одной инструкции в строке. Диски пронумерованы числами от 1 до n в порядке возрастания диаметров. Программа должна вывести минимальный (по количеству произведенных операций) способ перекладывания пирамидки.