Кроме того, переменная не будет оставаться неиспользуемой, попусту занимая место, когда она больше не нужна. Так как переменные пит определены в заголовке функции и во внешнем блоке, они находятся в области видимости всей функции и существуют вплоть до ее завершения.
Что, если вы объявите во внутреннем блоке переменную, которая имеет такое же имя, как переменная во внешнем блоке? Тогда имя, определенное внутри блока, соответствует переменной, которая применяется в этом блоке. Мы говорим, что имя скрывает внешнее определение. Однако когда поток управления покидает внутренний блок, внешняя переменная возвращается в область видимости. Эти и другие аспекты проиллюстрированы в листинге 12.1.
Листинг 12.1. Программа hiding . с
// hiding.с -- переменные в блоках #include int main()
(
int x = 30; // исходная переменная x
printf("x во внешнем блоке: %d по адресу %p\n", x, &x);
{
int x = 77; // новая переменная x, скрывающая первую x
printf("x во внутреннем блоке: %d по адресу %p\n", x, &x);
}
printf("x во внешнем блоке: %d по адресу %p\n", x, &x);
while (x++ < 33) // исходная переменная x
{
int x = 100; // новая переменная x, скрывающая первую x
x++;
printf("x в цикле while: %d по адресу %p\n", x, &x);
}
printf("x во внешнем блоке: %d по адресу %p\n", x, &x);
return 0;
488 глава 12
Вот результаты пробного запуска:
х во внешнем блоке: 30 по адресу 0x7fff5fbff8c8 x во внутреннем блоке: 77 по адресу 0x7fff5fbff8c4 x во внешнем блоке: 30 по адресу 0x7fff5fbff8c8 x в цикле while: 101 по адресу 0x7fff5fbff8c0 x в цикле while: 101 по адресу 0x7fff5fbff8c0 x в цикле while: 101 по адресу 0x7fff5fbff8c0 x во внешнем блоке: 34 по адресу 0x7fff5fbff8c8
Первым делом программа создает переменную х со значением 30, как показывает первый оператор printf(). Затем она определяет новую переменную х со значением 77, о чем сообщает второй оператор printf(). Это новая переменная, скрывающая первую переменную х, значение и адрес которой снова выводятся третьим оператором printf(). Данный оператор находится после первого внутреннего блока и отображает первоначальное значение х, демонстрируя тем самым, что эта переменная никуда не исчезала и не изменялась.
Вероятно, наиболее интригующей частью программы является цикл while. В условии проверки цикла while задействована исходная переменная х:
while (х++< 33)
Однако внутри цикла программа видит третью переменную х, т.е. ту, которая определена в рамках блока цикла while. Таким образом, когда в теле цикла используется выражение х+ + , в нем участвует новая переменная х, значение которой инкрементируется до 101 и затем отображается. По завершении каждой итерации цикла эта новая переменная х исчезает.
Далее в условии проверки цикла применяется и инкрементируется исходная переменная х, снова происходит вход в блок цикла, и опять создается новая переменная х. В этом примере переменная х создается и уничтожается три раза.
Обратите внимание, что для прекращения выполнения цикл должен инкрементировать х в условии проверки, т.к. инкрементирование х в теле цикла приводит к увеличению значения другой переменной х, а не той, которая задействована в условии проверки.
Хотя применяемый конкретный компилятор не использует повторно ячейку памяти переменной х внутреннего блока для версии х из цикла while, некоторые компиляторы делают это.
Назначение этого примера вовсе не в том, чтобы поощрять написание кода в таком стиле. Он служит лишь иллюстрацией того, что происходит, когда вы определяете переменные внутри блока. (Учитывая многообразие имен, доступных благодаря правилам именования С, выбор имени, отличающегося от х, не должен вызывать особые затруднения.)
Блоки без фигурных скобок
Упомянутая ранее возможность стандарта С99 заключается в том, что операторы, которые являются частью цикла или оператора if, квалифицируются как блок, даже если фигурные скобки ({ }) не указаны. Выражаясь более точно, полный цикл — это подблок содержащего его блока, а тело цикла — подблок блока полного цикла. Аналогично, one ратор if представляет собой блок, а связанный с ним оператор — подблок оператора if. Описанные правила влияют на то, где вы можете объявлять переменную, и на обласгь видимости этой переменной.
В листинге 12.2 показано, как это работает в цикле for.
Классы хранения, связывание и управление памятью 489
Листинг 12.2. Программа forc99.c

Читать дальше