Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции за I семестр 2014 - суммарный текст / Лекции за I семестр 2014 - суммарный текст.doc
Скачиваний:
209
Добавлен:
17.03.2016
Размер:
1.36 Mб
Скачать

Void fun(void);

void fun2(int a);

int a=10;

void main(){

cout<<a<<endl; // a=10

int a=20;

cout<<a<<endl; // a=20

do{

int a=30;

cout<<a<<endl; // a=30

} while(0);

cout<<a<<endl; // a=20

for (int i=0; i<1; i++) {

int a=40;

cout<<i<<endl; // i=0

cout<<a<<endl; // a=40

}

cout<<a<<endl; // a=20

fun();

fun2(a);

}

void fun(void){

cout<<a<<endl; // a=10

}

void fun2(int a){

cout<<a<<endl; // a=20

}

Некоторые уточнения:

  1. Параметры функции являются локальными переменными, их область действия - вся функция;

  2. Если переменная объявлена внутри круглых скобок какого-либо оператора (например, for (int i=0; i<n: i++) { … } ), то областью ее действия одни компиляторы считают этот оператор (вместе с его телом), а другие - весь блок, в котором он находится. Рекомендуется поэтому использовать подобное место объявления, только если это не может привести к двусмысленности.

  3. Область действия метки - вся функция (даже если метка лежит во вложенном блоке).

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

Замечание. Некоторые компиляторы не допускают переход с помощью goto внутрь области видимости переменной извне ("перескакивая" ее объявление), даже если сама эта переменная при этом не используется, т.к. это мешает им распределять память:

goto M;

int i;

M: // Может вызвать ошибку компиляции

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

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

14.2. Классы памяти объектов в языке Cи.

Класс памяти определяет время жизни объекта и место его размещения в памяти (относительно границ сегмента памяти, выделенного для программы в целом).

Существует 4 класса памяти: static (статический), extern (внешний), auto (автоматический), register (регистровый).

Объекты, имеющие класс памяти static, существуют (занимают место в памяти) в течение всего времени работы программы. Их место в памяти определяется на этапе компиляции. К ним по умолчанию относятся глобальные переменные.

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

Кроме того, общий размер стека должен быть задан на этапе компиляции и, таким образом, ограничен; в большинстве компиляторов по умолчанию (если не менять настроек) он равен всего лишь 1 мегабайт.

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

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

Класс памяти register похож на auto; но он рекомендует компилятору разместить (если возможно) переменную не в стеке, а непосредственно в регистрах процессора. Регистровая память позволяет увеличить быстродействие программы, но к размещаемым в ней объектам в языке Си (но не С++) не применима операция получения адреса «&».

Обычно класс памяти переменных определяется по умолчанию (static либо auto). Но программист имеет возможность поменять класс памяти объекта, указав требуемый класс при объявлении перед его типом (в пределах допустимого по смыслу - например, глобальная переменная не может быть auto или register).

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

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

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

Инициализация объектов классов памяти static и extern происходит один раз при запуске программы. Если инициализация не указана, объект обязательно инициализируется нулем (или пустым значением - для нечисловых переменных).

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

Пример 1:

#include <stdio.h>