Блочная структура программы

 

Как было отмечено выше, тело функции может быть блоком или составным оператором. Блок как совокупность описаний объектов и операторов может включать вложенные блоки, и тогда появляются внешние и локальные переменные по отношению к блоку, а также глобальные переменные, описанные вне функций программы.

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

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

Си-программа является отдельным программным модулем, который оформляется и записывается во внешнюю память как исходный файл с расширением “.c”, например, myprog.c.

 

Структуру модуля программы и области действия её объектов можно представить следующей схемой:

 

/* Глобальные объекты и описания */ /* Область действия */

директивы предпроцессора глобальная макроопределения

прототипы функций

описания типов

описания глобальных переменных

заголовок функции локальная

{внешние переменные блока;

операторы;

{ внутренний блок локальная

}

}

описания других функций

/* конец программы */

 

Пример. Применение вложенных блоков с одноимёнными переменными.

Программа:

 

void main ( )

{ int i=2; /* i – переменная внешнего блока */

int count=0; /* count – внешняя переменная */

while ( count <= i ) /* цикл внешнего блока */

{ int=0; /* i – локальная переменная внутреннего блока */

count++; /* счётчик циклов */

printf ( “В цикле: count=%d; i=%d\n”, count, i );

}

/* конец внутреннего блока, возврат к переменной i внешнего блока */

printf ( “Вне цикла: count=%d, i=%d”, count, i );

}

 

Результат программы:

В цикле count=1 i=0

В цикле count=2 i=0

В цикле count=3 i=0

Вне цикла count=3 i=2

 

Программист может явно задать атрибуты области действия и времени жизни с помощью спецификаторов классов памяти (хранения): для переменных (auto – локальный, register – регистровый, static – статический, extern – внешний) и для функций (static, extern).

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

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

 

Пример. Использование статических переменных.

Программа:

 

void example (int c); /* прототип функции */

 

void main ( ) /* главная функция */

{ int count; /* локальная переменная блока */

for (count=9; count >= 5; count -= 2) /* цикл счетчика */

example (count); /* вызов функции */

}

 

void example (int c) /* заголовок функции */

{ int f=1; /* локальная переменная */

static int stat=1; /* статическая переменная */

printf (“c=%d, f=%d, stat=%d\n”, c, f ,stat);

stat++; /* изменение статической переменной */

}

Результаты программы: c=9, f=1, stat=1

c=7, f=1, stat=2

c=5, f=1, stat=3