Институт №8 МАИ

1 день. Динамизм, ссылочный тип

Вопросы экзамена


Глава 4. Распределение памяти

4.1 (2) Статические и динамические объекты программ

Свойства объектов делят на статические и динамические.

Статические свойства неизменны при любом исполнении их области действия. Их можно определить по тексту программы, без её исполнения:

Динамические свойства и связи изменяются в процессе исполнения области действия.

Например:

Статические и динамические характеристики иначе называют характеристиками компиляции и выполнения.


Динамизмуровень изменчивости характеристик объектов языка — одно из важнейших свойств языка, подразумевающее ряд концепций: статическую и динамическую.

Она не исключает прогнозирования и контроля, но и не связывает их жестко со структурой текста программы.

Объект динамический, если память выделяется во время runtime и её объем меняется.

Неограниченный динамизм присущ не только всем машинным языкам, но и ЯП высокого уровня (Lisp, Basic, APL, Python).

При этом неограниченная статика невозможна, потому что значения переменных в программе должны меняться. Но все остальные характеристики могут быть статичны.

Статические программы надежны, потому что в них дано избыточное описание программы.

Статические языки более тяжеловесны, их описания объёмнее.

Объект статический, если память выделяется в процессе компиляции и её объем не меняется от начала до конца выполнения программы.

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


4.2 (3) Ссылочный тип

© Любой строгий язык требует предварительного описания.

В языках со строгой типизации, например в Паскале, динамический объект не имеет собственного имени (имя в спец. разделе программы).

Динамический объект не именуют, а обозначают посредством ссылки на него. Переменная-ссылка имеет свой ссылочный тип, в Паскале это тип var.

При этом сама ссылка — это статический объект, занимающий одно машинное слово.


© Переменная создаётся компилятором.

Ссылочный тип является скалярным и имеет прямую аппаратную поддержку.

Он включает в себя конкретные ссылки на объекты указуемого типа, созданные в основной памяти в процессе выполнения программы.

Ссылки в Паскале строго типизированы, и не следует их считать универсальными адресами областей памяти.

image


© Тип — это два связанных множества.

Ссылочные типы — это множества значений, указывающих на объекты целевых типов. Разные указуемые типы порождают разные ссылочные типы, множества значений которых не пересекаются.

Однако пустое ссылочное значение nil принадлежит любому их ссылочных типов. Оно указывает на отсутствие связи с объектом. Следует заметить, что nil не является неопределённым значением _ | _


Ссылочный тип может быть именованным и неименованным.

На Си неименованный случай записывают так:


typedef T* pointer;
pointer p
T* pl;

Обрабатывая описание переменной p, компилятор выделит место для хранения значений в основной памяти (одно машинное слово).

При этом память для ссылки остаётся в состоянии до её предыдущего использования, т.е. содержит последовательность 0 и 1, или неопределённое значение _ | _

Если компилятор не контролирует использование неопределенных значений, последовательность 0 и 1 может интерпретироваться как ссылка на объект, что может привести к непредсказуемому эффекту (появляется доступ к случайной области памяти).


Для переменных одного ссылочного типа определены операции присваивания и разыменования и отношение равенства.

Если результатом сравнения p = nil является значение true, то ссылочная переменная P не указывает ни на какой объект. Разыменование обеспечивает доступ к значению на ссылаемый объект.

В Си разыменование обозначается звёздочкой слева от него (*p). Разыменование имеет аппаратную поддержку в любом современном процессоре (косвенная адресация).

Динамические объекты порождаются при выполнении встроенных процедур Паскаля и Си (new и malloc), фактическим параметром которой является ссылка на элемент этого типа.

В Си все процедуры являются функциями, поэтому Malloc возвращает указатель на выделенную область памяти как значение самой функции.

В C++ динамические объекты порождаются оператором языка new, который вызывает констркутор объекта, выполняющий его инициализацию.

Инициализация — это запуск процессов, получение ресурсов, а не только установление начальных значения полей объекта.


При работе процедуры new память для объектов выделяется из “кучи” — области основной памяти, зарезервированной для этой цели. Переменной-ссылке при помощи ОС и язы присваивается значение начального адреса этой области.

Размер кучи в системе ограничен значением, заданным при компиляции программы. Поэтому при многократном вызове процедуры new может наступить момент, когда вся память, отведённая для динамических переменных, будет исчерпана, и программа не сможет продолжить работу.


© Мусор - это когда создаём
- динамические объекты и забываем их удалять.
- Тогда программа начинает своппить и трэшить.
- Это когда виртуальная память
- занята собой, а не полезным действием.

В Си ссылочный тип хорошо согласован с целым, а целый - со ссылочным. Поэтому ввод-вывод ссылочных переменных осуществяется обычными функциями scanf и printf (спецификация формата %p).

Ссылочные переменные особенно опасно оставлять неинициализированными.

Используя вариантные записи или объединения, можно наложить в памяти ссылочную и целую переменные и распечатать целочисленное значение ссылки.


#include <stdlib.h>

typedef union
{
	int val;
	int* ptr;
} ptr2int;

int main(void)
{
	int* pi = malloc(sizeof(int));
	*pi = 314;
	ptr2int p2i;
	p2i.ptr = pi;
	printf("Значение %d находится по адресу %d", *pi, p2i.val);
	free(pi);
}

В Си ссылочный тип идентичен адресному, а тот согласован с целым, поэтому ссылки можно вводить для задания абсолютных адресов:


printf("Значение %d находится по адресу %d", *pi, pi);

Константы можно порождать и уничтожать динамически, т.е. постоянство значения не означает фиксированного времени существования.


const int* pci = new int(100); // Указатель на константу со значением 100

*pci = 150; // Ошибка, пытаемся изменить константное значение
pci = new int(200); // Указатель на новую константу со значением 200


int const* cpi = new int(100); // Неизменяемый указатель

*cpi = 150; // Теперь по адресу cpi находится число 150
cpi = new int(200); // Ошибка, пытаемся изменить константный адрес

const int const* cpci = new int(100); // Неизменяемый указатель на константу

*cpci = 150; // Ошибка!
cpci = new int(200); // Ошибка!

Разыменование - переход от ссылки объекта к самому объекту.


Блочная структура с локальными переменными — пример неявного динамического распределения памяти, выполняемого языковой средой при входе и выходе из блока.


© Как и во всяком типе, в ссылочном есть теоретико-множественная часть.

© Вариантные записи - брешь паскаля! (они же union в Си)