Размещение программ и данных в памяти
Компилятор языка программирования генерируют код, который во время выполнения хранится в оперативной памяти так же, как и обрабатываемые данные. Программа после загрузки в оперативную память имеет следующую структуру:
| = |
| + |
| + |
| |||||||||
+ | |||||||||||||||
|
Статическое размещение данных в памяти (в сегменте данных или сегменте стека) осуществляется по формуле:
Определение Объявление = инициализация;
int i=1; // тип идентификатор=значение
Время жизни переменных -- это время, в течение которого переменная хранится в определенной области памяти. Время жизни переменных полностью определяется программистом. С понятием время жизни тесно связано понятие видимости (действия) переменных, которое бывает:
|
|
- глобальное, когда в любой момент во время работы с переменной всегда ассоциирована область памяти и обратиться к ней можно из любой точки программы;
- статическое, когда во время работы с переменной ассоциирована область памяти, но обратиться к ней можно только из определенных точек программы;
- локальное, когда при каждом входе в блок операторов { } для хранения переменной выделяется область памяти, а при выходе память освобождается и переменная теряет свое значение.
Для управления статическим размещением переменных в памяти, их временем жизни и областью видимости язык программирования C++ предоставляет понятие классов памяти и рад ключевых слов модификаторов типа:
- extern используется для определения глобальных переменных. Память для переменных extern распределяется постоянно. Такая переменная глобальна для всех функций и доступна в любой точке программы. Значение переменной всегда сохраняется.
- static используется для определения статических переменных. Статические определения используются в случае если необходимо сохранять предыдущее значение при повторном входе в блок операторов { }.
- auto используются для определения автоматических переменных. Переменные определенные внутри функции или блока операторов { } по умолчанию являются автоматическими. При входе в блок { } программа автоматически располагает переменную в сегменте стека. При выходе из блока память освобождается, а значения теряются.
- register используются для определения регистровых переменных. Переменные с классом памяти register, ассоциируются со скоростными регистрами памяти процессора. Но это не всегда возможно, поэтому часто компилятор преобразует такие переменные к классу auto.
Переменные extern и static явно не инициализированные программистом устанавливаются системой в нуль. Переменные auto и register не инициализируются и могут содержать "мусор".
|
|
Указатели и ссылки
На хранение адреса в современных вычислительных системах отводится 32 бита (4 байта) или 64 бита (8 байт). Это значит, что теоретически программы могут управлять памятью объемом около 4096 Мб (а для 64-разрядных систем - около 16777215 Тб). Для работы с памятью каждая из её ячеек нумеруется.
Пусть для хранения переменной i типа int отводится 4 байта. Тогда структура хранения этой переменной в оперативной памяти может иметь следующий вид:
Адрес ячейки памяти | Содержимое ячейки памяти |
...... | ......... |
0x0012FF70 | |
0x0012FF71 | |
0x0012FF72 | |
0x0012FF73 | |
0x0012FF74 | ......... |
....... | .......... |
Указатель (pointer) - это переменная (особого вида), предназначенная для хранения адреса объекта (адреса ячейки памяти, в которых хранится значение переменной). Диапазон значений для любого указателя включает специальный адрес 0 (null) и диапазон положительных целых чисел, который интерпретируется как машинные адреса.
Рассмотрим пример работы с указателем:
int *p; // переменная типа указателя
int i=2;
p=&i; // после выполнения p=0x0012FF70
Для получения адреса ячейки памяти, в которой хранится переменная, и последующей инициализации переменной типа указатель использовалась операция получения адреса (&). Таким образом, значение переменной p представляет собой адрес ячейки (указатель на то место в памяти), в которой хранится значение переменной i.
Язык программирования предоставляет нам возможность применять к указателям арифметические операции:
int j;
j=*p; // операция получения значения по указателю (* или разыменование)
int t=*p+1; // t будет равно 3
p++; // что будет?
Для получения значения переменной хранящейся в ячейке, на которую указывает указатель использовался оператор разыменования (*).
Ссылка (referenсe) - это переменная (особого вида), которая представляет собой альтернативное имя (псевдоним, alias) другой переменной.
int i=1;
int& r=i; // r - новое альтернативное имя для переменной i. r и i размещены (ссылаются) на одно и то же место в памяти
int x=r; // x=1
r=2; // i=2 тоже
r++; // чему равно значение перемнных r и i?
Особенность ссылок заключается в том, что ссылку нельзя объявить без инициализации, она сразу должна на что-то ссылаться, то есть быть псевдонимом для какого-то объекта. Псевдонима для "ничто" не может существовать.