Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции за I семестр конспект Гуревича для C++ B....doc
Скачиваний:
11
Добавлен:
21.11.2018
Размер:
1.3 Mб
Скачать

13.5. Классы памяти объектов в языке 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>

void f1(int);

void main(void)

{

f1(5);

}

void f1(int i)

{

int m=0;

puts(" n m p ");

while (i--) {

static int n = 0;

int p = 0;

printf(“ %d %d %d \n”, n++ , m++ , p++);

}

}

В результате выполнения программы получим:

n m p

0 0 0

1 1 0

2 2 0

3 3 0

4 4 0

Статическая переменная n будет создана в сегменте данных ОЗУ и проинициализируется нулем только один раз при первом выполнении оператора, содержащего ее определение, т.е. при первом вызове функции f1. Автоматическая переменная m инициализируется при каждом входе в функцию. Автоматическая переменная р инициализируется при каждом входе в блок цикла.

Задача 3. Условие задачи 2, но в начале каждой строки из звездочек выводить ее порядковый номер.

Функция st() примет вид:

void st(void){

static int k;

cout<<"\n"<<++k<<") ********************************\n ";

}

Результат работы программы (подчеркнуто число, введенное человеком):

Vvedite x :

3

1) ********************************

sin=0.14112

2) ********************************

cos=-0.989992

3) ********************************

tg=-0.142547

4) ********************************

ctg=-7.015253