Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pascal.doc
Скачиваний:
32
Добавлен:
12.03.2016
Размер:
3.29 Mб
Скачать
      1. Расположение информации в оперативной памяти. Адреса

Этот и следующий параграфы носят ознакомительный характер.

Раньше я уподоблял оперативную память тетрадному листу в клеточку. Каждая клетка - байт. Теперь я уподоблю ее многоэтажному небоскребу. Каждый этаж - байт.

Как и положено этажам, байты имеют номера. Эти номера называются адресами. Самый "нижний" байт имеет адрес 0, следующий - 1, следующий - - 2 и т.д. Если память вашего компьютера имеет объем 1 Мегабайт, то вы сами можете вычислить адрес последнего байта, учитывая, что 1 Мегабайт = 1024 Килобайта, a 1Килобайт = 1024 байта. Приняты сокращения: Мегабайт - М, Килобайт - К. Имейте в виду, что во многих книгах адреса записываются не в привычном нам виде, а в так называемой шестнадцатеричной системе счисления.

Во время выполнения вашей программы, написанной на Паскале, в памяти находится самая разная информация. То, что относится к паскалевской программе, располагается "по этажам" в следующем порядке:

байт с адресом 1М-1

куча

стек

сегмент данных объемом 64К

откомпилированная программа

байт с адресом 0

Границы между некоторыми областями памяти не фиксированы и зависят от решаемой задачи и желания программиста. В сегменте данных располагаются переменные, массивы и другие типы данных вашей программы, описанные привычным вам способом в разделах VAR, CONSTи т.д. (без использования ссылок). Обратите внимание, что размер сегмента данных весьма невелик (не более 64К).Стек- область памяти, в которой располагаются данные, описанные внутри процедур (этого мы пока не делали, об этом - в Глава .2).Куча- область памяти, в которой располагаются данные, описанные при помощи ссылок.

      1. Ссылки

Пусть вы хотите использовать следующий массив:

VAR a: array[1..200, 1..200] of Integer;

Давайте подсчитаем, сколько байтов в памяти займет этот массив. Одно число типа Integer занимает 2 байта. Получаем 200*200*2 = 80000 байтов. В сегменте данных массив не умещается, значит привычным образом работать с ним нельзя. Использование ссылок позволяет разместить его в куче (по английски - heap), имеющей гораздо больший размер.

Я привел лишь один из доводов в пользу применения ссылок. А поближе познакомимся мы со ссылками на простом примере. Задача: Вычислить и напечататьy=a+b, гдеaиb- целые числа 2 и 3. Вот традиционная программа для решения этой задачи:

VARa, b, y : Integer;BEGINa:=2; b:=3; y:=a+b; WriteLn (y)END.

А теперь потребуем, чтобы число 2 и результат 5 размещались в куче (впрочем, строго говоря, не обязательно в куче). Вот программа со ссылками:

VAR b : Integer; a,y : ^Integer; BEGIN New(a); New(y); a^ := 2; b:=3; y^ := a^ + b; WriteLn (y^) END.

Пояснения: Все, что вышеBEGIN, выполняется на этапе компиляции: Строкаa,y:^Integerприказывает отвести в памяти в сегменте данных две ячейки, но не для будущих чисел 2 и 5, а для адресов ячеек из кучи, в которых эти самые 2 и 5 предполагается хранить. Итак, будущие значенияaиy- не числа 2 и 5, аадресаячеек для этих чисел или, по-другому,ссылкина ячейки для этих чисел. Пока же адреса эти не определены.

Все, что ниже BEGIN, выполняется на этапе выполнения программы: При помощи обращений к процедуреNew(New(a)иNew(y) ) мы идем дальше и придаем переменнымaиyзначения конкретных адресов памяти, то есть отводим для будущих чисел 2 и 5 конкретное место в памяти. Таким образом, мы сталкиваемся с новым для нас явлением - место в памяти отводится не на этапе компиляции, а на этапе выполнения программы. В Паскале имеются средства и освобождать это место на этапе выполнения программы (процедураDispose, на которой я не буду останавливаться). Называется все этодинамическим распределением памятии сулит выгоды экономным создателям программ, использующим большие объемы разных данных в разные моменты выполнения программы.

Оператор a^:= 2идет еще дальше и посылает в ячейку, адрес которой находится в ячейкеa, число 2. Обозначается такая ячейка -a^. Если бы мне вздумалось написатьa:=2, это бы значило, что я хочу послать в ячейкуaадрес равный двум, что вполне возможно, но синтаксически неверно, так как численные значения адресов задаются по-другому.

Смысл следующих двух операторов очевиден.

Подведем итог. Значок ^, поставленный перед типом (например,^Integer), означает новый ссылочный тип, значения которого обязаны быть адресами переменной (или ссылками на переменную) исходного типа (в нашем случаеInteger).

Значок ^, поставленный после переменной ссылочного типа (например,a^), означает переменную, на которую ссылается исходная переменная (в нашем случае исходная переменнаяa).

Вот еще некоторые возможные операции со ссылками (без особых пояснений):

TYPED =array[1..10]ofReal; DP = ^D; Int= ^Integer;VARi, j : Int; { i, j - адреса целых чисел} m : DP; { m - адрес первой ячейки массива из 10 вещ. чисел}BEGINNew(i); New(j); New(m); i^:=4; j^:=3; j:=i; {Теперь j и i содержат адреса одного и того же числа - 4} WriteLn(j^); {поэтому будет напечатано число 4} m^[9]:=300 {Девятый элемент массива становится равным числу 300}END.

Вернемся к задаче о размещении большого массива. Поскольку Паскаль вслед за MS-DOSзапрещает не только описывать, но также, естественно, и ссылаться на структуру, объемом превышающую 64К, то ссылаться сразу на весь двумерный массив не выйдет и поэтому программа получится непростой:

TYPEa =array[1..200]ofInteger; ap = ^a; a2 =array[1..200]ofap;VARx : a2; {x - массив из 200 адресов (каждый - ссылка на строку из 200 элементов

исходного массива)}

BEGINfori:=1to200doNew(x[i]); {Место для массива отведено} ............ x[128]^[35]:=800; {Присвоено значение элементу массива} .............END.

В заключение упомяну, что ссылки полезны еще тем, что позволяют организовывать в памяти структуры переменной длины, такие как списки, деревья и т.п.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]