Время существования и область видимости переменных в C++

№76-1,

Технические науки

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

Похожие материалы

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

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

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

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

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

Локальную и глобальную переменные можно объявлять с одним и тем же именем. При этом объявление имени переменной в блоке скрывает объявление этого же имени во внешнем блоке или глобальное имя переменной. После выхода из блока имя внешней по отношению к этому блоку переменной восстанавливает свой смысл.

Таким образом, область видимости и область действия идентификатора несколько различаются, хотя чаще всего область видимости совпадает с областью действия.

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

#include 
#include 
using namespace std; // убрать эту строку в случае
                     // использования компилятора Borland C++ 5.02
int a=5;
int main()
{  int a=3; // скрывает глобальную переменную
   cout

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

Local block_1: 3
Global: 5
Local block_2: 7
Global: 5
Global after sum: 24
Local block_1: 3
Global: 24

Способа обращения к скрытой локальной переменной не существует. Как вариант в случае необходимости получения доступа к локальной переменной из вложенного блока можно рассматривать использование указателя:

int a=5;
int main()
{  int a=3, *p;
    p=&a;
    cout

Управлять областью видимости и временем существования переменных (или других объектов) можно либо изменением места объявления переменной в программе, либо используя модификаторы (классы памяти) auto, register, extern, static, mutable. Если класс памяти не указан явным образом, он определяется компилятором исходя из контекста объявления переменной. Более подробно о продолжительности хранения данных в памяти можно прочитать в [1].

Автоматическая (auto) переменная (как и константа) имеет локальную область действия и видна только внутри блока, в котором определена. Для такой переменной память выделяется при входе в блок, а после выхода из блока выделенная для переменной память считается свободной (переменная уничтожается). Если спецификатор класса памяти при описании переменной не указан, то переменная в блоке по умолчанию считается автоматической, поэтому задавать его явным образом для локальных переменных не имеет смысла.

Регистровая (register) переменная отличается от автоматической только памятью, выделяемой для ее хранения. Регистровая переменная хранится (по возможности) в регистрах процессора, и поэтому доступ к такой переменной осуществляется гораздо быстрее (переменная класса памяти auto хранится в оперативной памяти). Если свободные регистры памяти отсутствуют, то регистровая переменная становится автоматической.

Внешняя (extern) переменная является глобальной переменной, однако модификатор extern означает, что переменная будет объявлена (без слова extern) в другом месте программы или другом файле, где ей и будет выделена память. Поэтому такой класс памяти используется для создания переменных, доступных во всех модулях программы, в которых они объявлены. Пример:

#include 
#include 
using namespace std; // убрать эту строку в случае
// использования компилятора Borland C++ 5.02
extern int a;   //объявление переменной a
int main()
{  cout

Статической (static) переменной (или константе) выделяется память после ее объявления и сохраняется до конца выполнения программы. Время жизни такой переменной — постоянное. Такие переменные при объявлении по умолчании инициализируются нулевыми (арифметические типы) или пустыми значениями. В зависимости от места объявления, статические переменные могут быть как глобальными, так и локальными.

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

#include 
#include 
using namespace std; // убрать эту строку в случае
                                   // использования компилятора Borland C++ 5.02
int sum(int x)
    { static int s;
      for (int j=1; j

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

1= 1
1+2= 3
1+2+3= 6
1+2+3+4= 10
1+2+3+4+5= 15
1+2+3+4+5+6= 21
1+2+3+4+5+6+7= 28
1+2+3+4+5+6+7+8= 36
1+2+3+4+5+6+7+8+9= 45
1+2+3+4+5+6+7+8+9+10= 55

Сравните результат выполнения программы для случая, если вместо строки

static int s;

написать строку

int s; или int s=0;

Ключевое слово mutable задается в контексте использования спецификатора const. С его помощью можно указать, что некоторый элемент структуры (или класса) может быть изменен, даже если переменная типа структуры (или класса) объявлена со спецификатором const. В примере ниже показано, как это может быть реализовано.

#include "stdafx.h"
#include 
#include 
using namespace std;
struct client
{ mutable char name1 [20];
  char name2 [20];
  mutable double percent;
  mutable int sum;
  int year; };
  const client CL = {"Petrova", "Svetlana", 0.08, 5000, 2013};
int main()
{ system("cls");
  cout

Здесь спецификатор const структуры CL предотвращает изменение ее элементов, однако спецификатор mutable, предшествующий ее элементам name1, percent и sum, снимает с данных элементов такое ограничение.

Замечание. Если при описании объекта (или переменной) инициализатор не задан, то глобальным объектам, объектам из пространства имен и локальным статическим объектам присваивается нулевое значение соответствующего типа.

Список литературы

  1. Прата С. Язык программирования С++. Лекции и упражнения, 5-е изд.: Пер. с англ. – М.: Вильямс, 2007. – 1184 с.