Лекция 6 (1160839)
Текст из файла
13
Лекция 6
В C# и Java понятие указателя, вообще гворя, отсутствует.
Так как создатели С# пыталисьсделать его МОНО-языком(если есть .Net, то больше ничего не нужно , кроме C#, конечно )
Небезопасный код
В С# предусмотрена концепция небезопасных блоков – unsafe.Как мы знаем, в основном код, написанного на C# - управляемый(managed), он написан под .Net и более надежен. Но не весь код является управляемым: функции .Net не обеспечивают полного доступа ко всем ресурсам. Поэтому иногда приходится обращаться к API, который в большинстве сред формулируется в терминах WinApi. Для того, чтобы можно было обращаться к WinApi, была введена концепция небезопасного программирования(к нему можно обращаться из C#):
Пример небезопасного кода: библиотека времени выполнения (RTL), где можно обращаться к функциям malloc и free.
Естественным образом, все такие конструкции можно употреблять только в коде, который помечен словом unsafe.(В некоторых случаях такой код вовсе нельзя запускать, а иногда накладывается ряд ограничений на запуск)
Вообще говоря, в небезопасном коде существует довольно неочевидный переход между ссылками и адресами:
byte[] b byte * pb; //небезопасное преобразование
Согласно понятию ссылки b(b – ссылка на байтовый массив) – сама ссылка может плавать(в случае, когда сборщик мусора перемещает участки памяти), а следовательно, такое преобразование возможно только в том случае, когда мы находимся в пределах конструкции fixed:
fixed (byte *pb=b);//что происходит? Ссылка замораживается для сборщика мусора, и соответствующий блок памяти помечается как неперещаемый.
Мы не будем подробно рассматривать небезопасные конструкции языка С#. Просто запомним, что из соображений эффективности надежность их меньше.
Вывод: в C# и Java понятие указателя исчезло и превратилось в ссылку.
Как мы уже говорили, в C# существуют простые типы даных, а существуют референциальные(классы, массивы, интерфейсы), которые доступны только через ссылки.
Пример
X a;
Если этот текст написан не на C# и Java, то мы заводим обьект. А если на них – то мы заводим ссылку. Сами обьекты остаются анонимными, именованны лишь ссылки на них. Существование ссылки на обьект связано с вызовом оператора new:
X a:=new X();
(скобками мы подчеркиваем тот факт, что мы вызываем конструктор, даже если он и без параметров). Мы можем спокойно переприсвоить одну ссылку в другую.
Пример
String [] a;
String[] b=new String[N];
а=b;
В данном случае происходит поверхностное копирование, копирования памяти не происходит.
Любой обьект по определению находится только в динамической памяти, что сильно упрощает работу с ним.
С другой стороны, наличие сборщика мусора – не чистое благо, оно все же создает некоторые проблемы.
Концепция указателя в Ада-95
Концепция указателя в Ада-95 несколько изменилась(напомним, что Ада-83 – чистый строгий ЯП). В нем вдруг появилась возможность брать адреса из обьектов динамической памяти. Почему? Что же изменилось за 12 лет?
По большому счту ничего. Однако изменились внешние условия функционирования ЯП.(Ада изначально проектировалась как моноязык (моноЯП))
В 1983 году в Ада отсутствовала возможность вызова из Ада других программ, написанных на других ЯП. Если мы передаем аргумент по ссылкам, без получения адресов, то работать с Си-шными функциями практически невозможно В 1995 году такая возможность появилась. Каим образом она была реализована?
Создатели Ады остановились на слове access:
type PT is access T;
//pt – указатель обьект из динамической памяти типа Т
Если есть строчка
X: PT;
то можно сказать:
X:=new T;
При этом стандартным образом полуить адрес обьекта было нельзя(язык Ада все же изначально строгий ЯП). Что же делать, если мы хотим передать некоторый функции ее аргумент по адресу?
Чтобы не потерять надежность, придумали следующее
-
вся старая сигнатура остается
-
появляется другой тип данных
type PTT is access all T;
//указатель на все обьекты из динамической памяти типа Т
(сравните с type PT is access T; - без слова all )
Таким образом, мы можем ссылаться и на другие переменные. Однако адрес от переменной можно брать только том случае, если она обьявлена следующим образом:
Z: aliased T;
ZZ: T;
Операция Z access совместима с типом данных
type PTT is access all T;
и возвращает обьекты того же типа данных, что и обьект PTT.
То есть возможно такое:
XX:PT;
XX:=Z access;
Также разрешается: XX:=X;
А наоборот нельзя: X:=XX;//error!!!!!
Зачем это сделано?
1) данная коцепция не снижает уровень надежности старых программ
2)уовлетворены потребности, появившиеся вследствие изменения внешних требований к ЯП.
В современных ЯП ссылки, очевидно, это средства доступа к обьектам. В C#, Java и Delphi реализована референциальная модель обьекта.(Правда, в Delphi, в отличие от C# и Java, нет динамического сборщика мусора), поэтому очень важно, говоря об именах обьектов, понимать, что это не сами обьекты, а ссылки на них.
Замечание. Чем отличается понятие ссылки в С++ от ссылки в C#, Java и Delphi?
В С++ ссылка – это базисный тип данных. Это единственный тип данных, кторый был добавлен в С++ относительно Си. Какие операции применимы к ссылкам в таких ЯП, как C#, Java и Delphi, чем отличается ссылка и указатель(в Delphi присутствует еще и указательный тип данных – унаследован от языка Pascal)
1) присваивание – работает и для указателя, и для ссылки
2) разыменование – для ссылки неприменимо. Ссылки по оперделению не разыменовываются.
Кроме присваивания, к ссылке применима всего одна операция: обращение.
Д оходя до операции . (точка), компилятор сам вставит разыменование.
Пусть у нас есть тип записи6
T is record
A: T1;
B: T2;
end record
type PT is acces T;
Сама по себе операция разыменования для ссылки скрыта, она выполняется по умолчанию:
Интересно, что в языке Оберон операция разыменования тоже отсутствует.
Таким образом, единственная операция над ссылкой, которую может выполнить сам пользователь – это присваивание, а ссылка выступает как некоторое имя обьекта.
С языке С++ единственная операция, применимая к ссылкам – это инициализация. Инициализация происходит путем присваивания ссылке некоторого обьекта. При этом ссылка инициализируется адресом обьекта. Происходит инициализация на этапе динамического распределения памяти. Единственный способ инициализации ссылки – в инициализаторе(несколькими строчками ниже)
X & t;//ошибка – ссылка не проинициализировалась, теперь всю жизнь будет непонятно чем.
X & t=a;
//теперь можно считать, что t – это второе имя обьекта а. Присваивая что-то в t, мы на самом деле работаем с обьектом а.
Допустима и такая ситация:
X * pa=new X();
X & t=*pa;//теперь у нашего обьекта, на который указвает указатель pa, появилось имя: t. У него можно брать адрес. Адрес t равен значению pa. Допустимо:
delete &t;
Таким образом, понятие ссылки в С++ сильно отличается от понятия ссылки в других ЯП,
С случае с функцией
f(X& t);
инициализация ссылки происходит в момент вызова функции:
f(a);
Глава 3. Составные типы данных
Пункт 3.1 О массивах
Самый популярный тип данных - массив(первый составной) – это астракция.
Последовательности однотипных элементов.
Какие операции применимы к массиву? Например,
-
индексирование(A[i]). Данная операция применима к обьекту массива либо к значению индексного типа.
[ ] : A, I->D
Индексирование – практически единственная операция, специфичная для массивов.
Чем отличается реализация массивов в разных ЯП? Рассмотрим некоторые свойства массивов в различных ЯП, например
-
какие атрибуты данных есть у типа даных «массив»
-
время сязывания
Атрибуты массива:
1) базовый тип
2) тип индекса(I)
3) диапазон индекса и связанная с ним характеристика: длина массива.(L..R)
Когда базовый тип связывается с массивом?(или, проще говоря, какоговремя связывания) Связывание во всех базовых типах происходит статически.
Когда «связывается» тип индекса? Тогда же, когда и базовый тип. Тоже статически.
Пример. 1995 год, язык C#, принято правило: массивы всегда индексируются типом integer. Данное решение было принято на этапе разработки спецификации языка.
Интересно: если взять C#, Java и Оберон – то во всех этих языках, ровно как и в С и С++ тип индекса всегда целочисленный. Более того, там зафиксирована и нижняя граница – 0. Почему в итоге разработчики «дошли» до этого?
В таких языках, где зафиксирована нижняя граница и тип индекса, остается при программировании задать только один атрибут - длину.
О длине массива
Длина – это статический или не статический атрибут? Когда мы фиксируем длину?
Возможно, как мы знаем, оба случая.
-
Длина – статический атрибут
-
Длина – динамический атрибут. В этом случае время сязывания может быь либо чисто динамическим, либо квазистатическим(в случае, если значение атрибута длины было получено в runtime, но после не поменялось)
Во всех массивах в рассматриваемых нами языках длина может принадлежать одному из перечисленных типов. Реализация длины в том или ином варианте тесно связана с понятием эффективности.
Файлы на внешнем носителе – это последовательность байтов, не обязательно непрерывная. Одна из принципиальных особенностей массива заключается в том, что это ВСЕГДА НЕПРЕРЫВНАЯ последовательность байтов, и если разрешить массиву вести себя «динамически», возникнут проблемы с распределением памяти.
Однако статически выделять память плохо, негибко. Поэтому в основном в современных ЯП длина массива квазистатическая.
Массив в С++(традиционный)
T[ ] a;
//a – это ссылка на массив
new T[N];
Теперь у нас есть элементы массива от 0 до N-1. Длина массива изменена быть не может(иначе это привело бы к неудобству распределения памяти).
Если намм нужна последовательность однотипных элементов, которая может менять свою длину – лучше воспользоваться коллекциями. В С++ коллекции можно обнаружить библиотеке STL. В C# - в System.Collections а также в System.Collections.Generic. В Java тоже есть понятие коллекции – оно находится в соответствующем пакете.
Заметим, однако, что в базис языка программирования данные средства не входят!
О сортировке элементов массива
Очевидно, не существует оптимального для всех алгоритмов метода сортировки.
Для люого априори взятого алгоритма распределения памяти можно подобрать послеовательность запросов, делающих его малоэффективным. Следовательно, так как для коллекций универсальных алгоритмов нет, а для базовых типов данных(массива – непрерывной последовательности байтов, к примеру) , есть, включать коллекции в базис языка нелогично.
Массивы в различных ЯП
В языке Pascal различные типы несовместимы, и это огромный недостаток данного языка. Это еще раз подчеркивает, что Pascal – язык не для индустриального программирования. Комплиятор Pascal при индексировании выполняет квазистатический код проверки. Это эффективно, надежно, но не гибко.
Следующий этап – Modula-2. Подход почти что как в Pascal, за исключением одного новшества: появляются формальные параметры: стало можно передавать открытые массивы – массивы, у которых зафиксирован только тип – но только в качестве формальных параметров. Средство разрешения простое и локальное.
Синтаксис открытого массива:
TYPE arr=ARRAY INDEX of D;
TYPE Index =[1..N];// квадратные скобки – это принадлежность диапазона
А синтаксис массива следующий:
ARRAY OF D;
(TYPE arr=ARRAY OF D) D->0..N-1
Для типа CARDINAL:
Index=CARDINAL[0..N];
//все это, заметим, чисто статически!
Так как типом индекса должен быть диапазонный тип, он легко сводится к целому.
А еще у открытого массива есть функция HIGH
Пример использования массива в Modula-2
//процедура суммирования элементов массива
Характеристики
Тип файла документ
Документы такого типа открываются такими программами, как Microsoft Office Word на компьютерах Windows, Apple Pages на компьютерах Mac, Open Office - бесплатная альтернатива на различных платформах, в том числе Linux. Наиболее простым и современным решением будут Google документы, так как открываются онлайн без скачивания прямо в браузере на любой платформе. Существуют российские качественные аналоги, например от Яндекса.
Будьте внимательны на мобильных устройствах, так как там используются упрощённый функционал даже в официальном приложении от Microsoft, поэтому для просмотра скачивайте PDF-версию. А если нужно редактировать файл, то используйте оригинальный файл.
Файлы такого типа обычно разбиты на страницы, а текст может быть форматированным (жирный, курсив, выбор шрифта, таблицы и т.п.), а также в него можно добавлять изображения. Формат идеально подходит для рефератов, докладов и РПЗ курсовых проектов, которые необходимо распечатать. Кстати перед печатью также сохраняйте файл в PDF, так как принтер может начудить со шрифтами.