Область видимости переменных
Каждая переменная имеет определенную область видимости (scope). Область видимости представляет участок программы, в рамках которого можно использовать переменную.
Переменные бывают глобальными и локальными или автоматическими.
Глобальные переменные
Глобальные переменные определены в файле программы вне любой из функций и могут использоваться любой функцией.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
int n = 5;
void printn()
{
n++;
printf("n=%d \n", n);
}
int main(void)
{
printn(); // n=6
n++;
printf("n=%d \n", n); // n=7
return 0;
}
Здесь переменная n является глобальной и доступна из любой функции. При этом любая функция может изменить ее значение.
Автоматические переменные
Локальные или автоматические переменные определяются внутри блока кода (например, внутри функции) и существуют только в рамках этого блока. При входе в блок для этих переменных выделяется память (которую еще называют автоматическая память), а после завершения работы этого блока, выделенная память освобождается, а объекты удаляются.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void printn()
{
int n = 63;
n++;
printf("n=%d \n", n);
}
int main(void)
{
int a = 2;
printn(); // n=64
//n++; так сделать нельзя, так как n определена в функции printn
printf("a=%d \n", a); // a=2
return 0;
}
Здесь в функции printn определена автоматическая переменная n. В функции main определена автоматическая переменная a. При вне своих функций переменные недоступны. Например, мы не можем использовать переменную n в функции main, так как ее область видимости ограничена функцией printn.
К автоматическим переменным может применяться ключевое слово auto:
auto int a = 2;
Хотя это необязательно, так как любая переменная, определенная на уровне функции или блока кода, уже считается автоматической.
Сокрытие переменных
Автоматические переменные, определенные внутри блока кода, могут скрывать внешние переменные с тем же именем:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int n = 5;
int main(void)
{
int n = 10;
printf("n=%d \n", n); // n=10
{
int n = 20;
printf("n=%d \n", n); // n=20
}
return 0;
}
Здесь определено три переменных с именем n. Автоматическая переменная n, определенная на уровне функции main (int n = 10;) скрывает глобальную переменную n. А переменная n, определенная на уровне блока, скрывает переменную, определенную на уровне функции main.
Статические переменные
Кроме глобальных и автоматических есть особый тип переменных - статические переменные. Они определяются на уровне функций с помощью ключевого слово static. Если автоматические переменные определяются и инициализируются при каждом входе в функцию, то статические переменные инициализируются только один раз, а при последующих вызовах функции используется старое значение статической переменной.
Например, пусть у нас будет функция со стандартной автоматической переменной:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
void display()
{
int i = 0;
i++;
printf("i=%d \n", i);
}
int main(void)
{
display();
display();
display();
return 0;
}
Функция display вызывается три раза, и при каждом вызове программа повторно будет выделять память для переменной i, которая определена в функции. А после завершения работы display, память для переменной i будет освобождаться. Соответственно ее значение при каждом вызове будет неизменно:
i=1
i=1
i=1
Теперь сделаем переменную i статической:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
void display()
{
static int i = 0;
i++;
printf("i=%d \n", i);
}
int main(void)
{
display();
display();
display();
return 0;
}
К переменной был добавлено ключевое слово static, поэтому при завершении работы функции display переменная не уничтожается, ее память не очищается, наоборот, она сохраняется в памяти. И соответственно результат работы программы будет иным:
i=1
i=2
i=3
Регистровые переменные
Регистровые переменные фактически являются также автоматическими переменные, но при их определении используется ключевое слово register. Это слово сообщает компилятору, что данная переменная будет интенсивно использоваться в приложении, поэтому ее желательно поместить в регистр процессора, что увеличит быстродействие.
Ключевое слово register применяется к переменным:
1
register int x = 8;
И к параметрам функции:
1
2
3
4
void display(register int a)
{
printf("a=%d \n", a);
}
Однако использование слова register еще не является гарантией, что переменная действительно будет помещена в регистр, так как много зависит от аппаратной части компьютера и установленных для нее ограничений. В то же время если аппаратные возможности не поддерживают регистровых переменных, то слово register просто будет игнорироваться, и его использование не вызовет ошибку.