лекции (2009), страница 3
Описание файла
Текстовый-файл из архива "лекции (2009)", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр 3 страницы текстового-файла онлайн
• Метка
Указатели
Пробле
мы
строгих
и
нестрог
их
указател
ей:
• Уд
аление
памяти
(Dispose
(p : PT))
не в
своё
время,
что
приводи
т к появлению «висячих ссылок» - указателей, которые должны на что-то указывать, но не указывают.
• Накопление мусора – памяти, на которую не указывает ни один указатель.
P,P1 : PT;
New( P );
New( P2 );
P := P2; {порождение мусора}
Dispose(P2); {P – «висячая ссылка», попытка обращения к памяти, которую она занимает, приведёт к ошибке}
Различают системы с динамической сборкой мусора и без таковой.
Строгий язык с динамической сборкой мусора довольно надёжен.
От висячих ссылок защиты нет
Ада
В чистой Аде есть только new(p). В модуле STANDARD есть UNCHECKED_DEALLOCATION(p) – подчёркивается
небезопасность этой операции
Примеры ошибок:
T *p;
Строгие
Стандартный Паскаль, Модула-2, Ада, Оберон
(со сборкой)
Pascal
Type PT = ^T;
{Modula-2
Type PT = pointer to T;}
var
i :T;
Инициализировать указатель можно только
двумя способами – либо другим указателем,
либо выделением новой памяти NEW(p : PT);
Поэтому все данные чётко разделяются на
именованные, либо не именованные.
Указатель служит для работы с анонимными
данными в динамической памяти.
Смысл – избежание части ошибок
Не строгие
C, C++, Turbo Pascal
Можно получать адрес любого объекта с
помощью операции взятия адреса «&»
Существует абстрактный указатель «void *»
T * => void * автоматически
void * к T * автоматически не приводится
T * p;
void *pp;
pp = p;
p = (T *)pp;
Void f()
{
T x;
P = &x; //!!!адрес локальной переменной!!!
}
void Foo()
{
f();
free(p); //!!!попытка освобождения невыделенной памяти!!! – выдастся ошибка
}
new(p1);
p := p1;
Dispose(p1); {р «висит»}
Для Java, C# - указатели трансформировались в ссылки
Несколько слов о языке Small Talk
Последовательность действий при вычислении значения выражения «2+2»:
1.
Посылка сообщения «+» обекту 2 с параметром 3
2.
В классе integer ищется по таблице методов доступа обработчик сообщения «+» и вызывается
3.
Обработчик отрабатывает и возвращает новый объект «5»
Лекция. Ульянов А.В.
Указатели.
В чем опасность использования: низкоуровневое программирование.
Если используется динамическая сборка мусора, тогда проще.
Так процедура UNCHECKED_DEALLOCATION(P) является аналогом delete(p), dispose(p) в ЯП, где используется
динамическая сборка мусора.
C#, Java - понятие указателя отсутствует (точнее в C# такое понятие есть, но только в небезопасных блоках
unsafe)
managed – управляемый код.
Функции .net не дают все возможности по использованию ресурсов ОС, отсюда приходится обращаться к
возможностям Win API.
unsafe – код, где появляются новые конструкции, С RTL (как будто внутри языка С).
Обращаться к ним можно тоже только из unsafe. Функции, использующие это, тоже помечены как unsafe.
unsafe {…}
byte []b можно объявить как byte *b и использовать в вышеуказанном блоке.
Как работает динамическая сборка мусора:
Менеджер динамической сборки мусора запрашивает память, ее дают, а как только заканчивается, работает
динамический сборщик мусора. Он-то и находит все неиспользуемые куски памяти, сводит к одному блоку.
Именно поэтому ссылка на byte может плавать и нельзя рассчитывать на то, что ее адрес будет постоянным.
Потому преобразование byte[] в byte * возможно только блоке (ссылка замораживается):
fixed (byte* pb = b) {…}
C#, Java – понятие указателя исчезло и превратилось в понятие ссылки.
Типы значения,
Референциальные ТД (классы, массивы, интерфейсы) – к ним обращение только по ссылке.
X a; // Если в C#, Java – то объект является ссылкой и пока не существует.
a = new X(); //Вызов конструктора обязателен.
string[] a;
string[] b = new string[N];
a = b; // Присваивание ссылок, а не копирование.
Понятие указателя в Ада 95(83).
Ада 83:
PT – указатель на тип T.
type PT is access T;
x: PT;
x := new T;
y: T; - Получить адрес у стандартными средствами нельзя.
Ада 95:
Если: type PT is access T;
То инициализация возможна только так:
x: PT;
x := new T;
Если же: type PTT is access all T; (на все объекты типа Т)
xx: PTT;
xx := new T;
Однако можно ссылаться и на другие переменные:
z: aliased T;
zz: T;
z ’access – операция взятия адреса.
x := z’access; - нельзя, т.к. без aliased.
xx := z’access; -можно.
xx := x; - можно.
x := xx; - нельзя.
В современных ЯП ссылки – это средства доступа к объекту.
В C#, Java, Delphi – имеются референциальные ТД.
“имена” = ссылки.
В С++ добавили отдельный базисный тип - ссылочный.
С точки зрения операций:
Чем различаются ссылка и указатель:
*(в С), ^ (M-2, P)
:= только к ссылкам разъименование объекта (и выполняется компилятором).
. – компилятор вставляет разъименование сам.
T is record
A: T1;
B: T2;
end record
type PT is access T;
X: Pt;
X.A; X.B; //разъименование делается компилятором.
X.all; // явное разъименование.
В С++ к ссылкам применяется единственная операция – инициализация (путем присваивания ссылки
внешнему объекту, по сути ссылка инициализируется адресом объекта).
X& t = a; // все, что можно делать с а, можно делать и с t.
X* pa = new X();
X& t = *pa;
&t == значению указателя pa.
delete(&t);
Если f(X&t) – тогда инициализируется в момент вызова функции.
Глава 3. Составные ТД.
П.3.1. Массивы.
Последовательность однотипных элементов.
D x … x Dn
A[i] – операция индексирования. i – индексное выражение.
Атрибуты массива:
1)
Базовый тип (тип элементов) – D
2)
Тип индекса (i)
3)
Диапазон индекса (длина)
В разных ЯП:
Связывание базового типа статически (везде).
Тип индекса – С/С++/С#/Java/Оберон – всегда тип int (статическое связывание).
Фиксируется нижняя граница значения индекса.
Длина – статическая и динамическая.
Динамическая – чисто-динамическая(можно изменить в любое время) и квазистатическая(значение
получено динамически, но изменять нельзя).
Массив всегда непрерывная последовательность байтов. Отсюда возникает проблема распределения памяти.
Можно длину сделать статической (жестко), оттого сделали квазистатической.
T[] a = new T[N]; //0..N-1
P,i,L..R(диапазон)
Стандартный Pascal:
Function SCAL( A,B: Arr): real;
Если диапазон для Arr от 1..N, то для массива от 0..N-1 работать будет не корректно(или вовсе не будет
работать).
A[i] – компилятор выполняет квазистатический контроль. (не очень-то гибко)
Модула-2:
Объекты данных массива (переменные). Формальные параметры массива (открытые массивы).
Понятие открытого массива: зафиксирован базовый тип.
Обычный массив:
TYPE Arr = ARRAY Index of D;