Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЗФ_ОАиП / Лекции ГГУ Скорины - Программирование.doc
Скачиваний:
179
Добавлен:
21.03.2016
Размер:
2.27 Mб
Скачать

20.5. Глобальные статические переменные

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

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

20.6. Локальные переменные

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

void f1 () {

int a = 0;

a = a + 1;

}

В данном примере, сколько бы раз не вызывалась функция, переменная a никогда не станет больше единицы.

Переменная с классом памяти auto автоматически не инициализируется. Она может быть проинициализирована явно при определении путем присвоения ей начального значения. Значение неинициализированной переменной с классом памяти auto считается неопределенным (точнее, случайным). При входе в блок под нее просто отводится память, прямо с тем содержимым, которое в ней было. В результате в неинициализированных локальных переменных оказывается «мусор» – непредсказуемые значения, которые к тому же могут меняться от вызова к вызову функции, поскольку зависят от предистории работы программы.

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

void f1 () {

int a; // объявление локальной переменной

f2(100);

}

void f2 (int b) {

b = 10;

a = 3; // ошибка, отсутствует объявление переменной

}

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

Также можно объявить локальную переменную в блоке: в начале блока или в середине. Переменная, объявленная в блоке, «прячет» любую другую переменную с таким же именем, описанную вовне.

void main() {

int x = 10;

int a = 5, b = 7;

if (a<b) { // начало вложенного блока

int y; // локальная для блока переменная

y = x+7;

printf("x = %d\n", x); // x = 10

printf("y = %d\n", y); // y = 17

int x; // описание новой переменной внутри блока

x = 20;

y = x+7;

printf("x = %d\n", x); // x = 20

printf("y = %d\n", y); // y = 27

}

printf("x = %d\n", x); // x = 10

// printf("y = %d\n", y); // ошибка – неопределенная переменная y

}

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

void main () {

...

}

void f1 () {

extern int x;// объявляем глобальную переменную, теперь ее можно

// использовать в этой функции, иначе компилятор выдал бы

x = 15; // ошибку, что переменная ещё не определена

}

int x = 5; // определение глобальной переменной

int getX () {

return x; // getХ видит переменную x

}

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

int getZ(void); // описание прототипа функции

int x = 5; // определение глобальной переменной

void main () { // БЛОК 1

extern int y; // объявляем глобальную переменную y

int a, b; // описываем локальные a и b

scanf("%d%d", &a, &b);

if (a < b) { // БЛОК 2

extern int z; // объявляем глобальную переменную z

int i = x + y + z; // описываем локальную i

printf("i = %d\n", i); // при вводе 1 и 2 получим 8

}

else { // БЛОК 3

int x = 0; // перекрывает глобальную x локальной x

int i; // это совсем другая локальная i, а не из блока 2

for (i=0; i<5; i++) { // БЛОК 4

int a = getZ()*i; // перекрывает переменную а из main()

x += a;

}

printf("x = %d\n", x); // при вводе 2 и 1 получим 20

}

}

int y = 1; // определение глобальной переменной

int z = 2; // определение глобальной переменной

int getZ () { // БЛОК 5

return z;

}

Вложенность блоков и локальные переменные блоков:

БЛОК

Доступные локальные переменные

Доступные глобальные переменные

1

a b

x y

2

a b i

x y z

3

a b x i

y

4

b x i a

y

5

x y z