мета-данные страницы
Загрузка не удалась. Возможно, проблемы с правами доступа?
Различия
Показаны различия между двумя версиями страницы.
| Предыдущая версия справа и слеваПредыдущая версияСледующая версия | Предыдущая версия | ||
| pascal:pointers [21/11/2009 18:12] – oca | pascal:pointers [21/11/2009 18:16] (текущий) – oca | ||
|---|---|---|---|
| Строка 2: | Строка 2: | ||
| FIXME | FIXME | ||
| + | ===== Использование указателей в Паскале ===== | ||
| + | |||
| + | http:// | ||
| + | |||
| + | Подведем некоторые итоги. Итак, динамическая память составляет 200…300 Кбайт или больше, | ||
| + | |||
| + | Посмотрим, | ||
| + | |||
| + | Казалось бы, эту проблему можно решить следующим образом: | ||
| + | |||
| + | var | ||
| + | |||
| + | i,j : Integer; | ||
| + | |||
| + | PtrArr : array [1..100, 1...200] of Real; | ||
| + | |||
| + | begin | ||
| + | |||
| + | for i := 1 to 100 do | ||
| + | |||
| + | for j := 1 to 200 do | ||
| + | |||
| + | new(PtrArr[i, | ||
| + | |||
| + | ……. | ||
| + | |||
| + | end. | ||
| + | |||
| + | Теперь к любому элементу вновь созданного динамического массива можно обратиться по адресу, | ||
| + | |||
| + | PtrArr[1,1] := 0; | ||
| + | |||
| + | if PtrArr[i, | ||
| + | |||
| + | Вспомним, | ||
| + | |||
| + | Выходом из положения могла бы послужить адресная арифметика, | ||
| + | |||
| + | Тем не менее, решить указанную задачу все-таки можно. Как мы уже знаем, любой указатель состоит из двух слов типа WORD, в которых хранятся сегмент и смещение. В Турбо Паскале определены две встроенные функции типа WORD, позволяющие получить содержимое этих слов: | ||
| + | |||
| + | SEG(X) – возвращает сегментную часть адреса; | ||
| + | |||
| + | OFS(X) – возвращает смещение. | ||
| + | |||
| + | Аргументом X при обращении к этим функциям может служить любая переменная, | ||
| + | |||
| + | var | ||
| + | |||
| + | р : Real; | ||
| + | |||
| + | begin | ||
| + | |||
| + | …… | ||
| + | |||
| + | new(p); | ||
| + | |||
| + | р := 3.14; | ||
| + | |||
| + | ……. | ||
| + | |||
| + | end. | ||
| + | |||
| + | то функция SEG(P) вернет сегментную часть адреса, | ||
| + | |||
| + | С другой стороны, | ||
| + | |||
| + | PTR(SEG, | ||
| + | |||
| + | можно создать значение указателя, | ||
| + | |||
| + | var | ||
| + | |||
| + | i, | ||
| + | |||
| + | PtrStr : array [1..100] of pointer; | ||
| + | |||
| + | const | ||
| + | |||
| + | SizeOfReal = 6; | ||
| + | |||
| + | begin | ||
| + | |||
| + | for i := 1 to 100 do | ||
| + | |||
| + | GetMem (PtrStr [i] , SizeOfReal*200) ; | ||
| + | |||
| + | ……. | ||
| + | |||
| + | {Обращение к элементу матрицы [i,j]} | ||
| + | |||
| + | pr := ptr(seg(PtrStr[i]), | ||
| + | |||
| + | ofs(PtrStr[i])+(j-1)*SizeOfReal); | ||
| + | |||
| + | if рr > 1 then | ||
| + | |||
| + | ……. | ||
| + | |||
| + | end. | ||
| + | |||
| + | Поскольку оператор вычисления адреса PR := PTR… будет, судя по всему, использоваться в программе неоднократно, | ||
| + | |||
| + | Пример | ||
| + | |||
| + | const | ||
| + | |||
| + | SizeOfReal = 6; {Длина переменной типа REAL} | ||
| + | |||
| + | N = 100; {Количество столбцов} | ||
| + | |||
| + | М = 200; {Количество строк} | ||
| + | |||
| + | var | ||
| + | |||
| + | i,j : Integer; | ||
| + | |||
| + | PtrStr: array [1..N] of pointer;. | ||
| + | |||
| + | s : Real ; | ||
| + | |||
| + | type | ||
| + | |||
| + | RealPoint =^Real; | ||
| + | |||
| + | {——————-} | ||
| + | |||
| + | Function AddrR(i,j: word): RealPoint; | ||
| + | |||
| + | {По сегменту i и смещению j выдает адрес вещественной переменной} | ||
| + | |||
| + | begin | ||
| + | |||
| + | AddrR := ptr(seg (PtrStr [i]), | ||
| + | |||
| + | ofs{ PtrStr [i]) + (j -1) * SizeOfReal) | ||
| + | |||
| + | end {AddrR} ; | ||
| + | |||
| + | {——————-} | ||
| + | |||
| + | Function GetR(i,j: Integer): Real; | ||
| + | |||
| + | {Выдает значение вещественной переменной по сегменту i и смещению j ее адреса} | ||
| + | |||
| + | begin | ||
| + | |||
| + | GetR := AddrR(i,j) | ||
| + | |||
| + | end {GetR}; | ||
| + | |||
| + | {——————-} | ||
| + | |||
| + | Procepure PutR(i,j : Integer; x: Real); | ||
| + | |||
| + | {Помещает в переменную, | ||
| + | |||
| + | begin | ||
| + | |||
| + | AddrR ( i , j ) : = x | ||
| + | |||
| + | end {PutR}; | ||
| + | |||
| + | {——————-} | ||
| + | |||
| + | begin {Main} | ||
| + | |||
| + | for i :=1 to N do | ||
| + | |||
| + | begin | ||
| + | |||
| + | GetMem (PtrStr [i] , M*SizeOfReal) ; | ||
| + | |||
| + | for j := 1 to M do PutR(i, j, Random) | ||
| + | |||
| + | end; | ||
| + | |||
| + | S := 0; | ||
| + | |||
| + | for i := 1 to N do | ||
| + | |||
| + | for j := 1 to M do | ||
| + | |||
| + | s := s +GetR(i,j); | ||
| + | |||
| + | WriteLn(s/ | ||
| + | |||
| + | end {Main} . | ||
| + | |||
| + | В рассмотренном примере предполагается, | ||
| ===== Процедуры и функции для работы с динамической памятью ===== | ===== Процедуры и функции для работы с динамической памятью ===== | ||
| Строка 74: | Строка 263: | ||
| MAXAVAIL | MAXAVAIL | ||
| + | |||
| + | Результат имеет тип LONGINT. За один вызов процедуры NEW или GETMEM нельзя зарезервировать памяти больше, | ||
| + | |||
| + | Функция MEMAVAIL. | ||
| + | |||
| + | Возвращает размер в байтах общего свободного пространства кучи. Обращение: | ||
| + | |||
| + | MEMAVAIL | ||
| + | |||
| + | Результат имеет тип LONGINT. | ||
| + | |||
| + | Процедура NEW. | ||
| + | |||
| + | Резервирует фрагмент кучи для размещения переменной. Обращение: | ||
| + | |||
| + | NEW ( ТР ) | ||
| + | |||
| + | Здесь ТР – типизированный указатель. | ||
| + | |||
| + | За одно обращение к процедуре можно зарезервировать не более 65521 байта динамической памяти. Если нет свободной памяти требуемого размера, | ||
| + | |||
| + | Процедура NEW может вызываться как функция. В этом случае параметром обращения к ней является тип переменной, | ||
| + | |||
| + | type | ||
| + | |||
| + | PInt =^Integer; | ||
| + | |||
| + | var | ||
| + | |||
| + | p: Pint; | ||
| + | |||
| + | begin | ||
| + | |||
| + | p := New(PInt); | ||
| + | |||
| + | …… | ||
| + | |||
| + | end. | ||
| + | |||
| + | При размещении в динамической памяти объекта разрешается в качестве второго параметра обращения к NEW указывать имя конструктора (см. гл.10). | ||
| + | |||
| + | Функция OFS. | ||
| + | |||
| + | Возвращает значение типа WORD, содержащее смещение адреса указанного объекта. Вызов: | ||
| + | |||
| + | OFS ( X ) | ||
| + | |||
| + | Здесь Х- выражение любого типа или имя процедуры. | ||
| + | |||
| + | Функция PTR. | ||
| + | |||
| + | Возвращает значение типа POINTER по заданному сегменту SEG и смещению OFS. Вызов: | ||
| + | |||
| + | PTR ( SEG, OFS ) | ||
| + | |||
| + | Здесь SEG – выражение типа WORD, содержащее сегмент; | ||
| + | |||
| + | OFS – выражение типа WORD, содержащее смещение. | ||
| + | |||
| + | Значение, | ||
| + | |||
| + | Процедура RELEASE. | ||
| + | |||
| + | Освобождает участок кучи. Обращение: | ||
| + | |||
| + | RELEASE ( PTR ) | ||
| + | |||
| + | Здесь PTR – указатель любого типа, в котором предварительно было сохранено процедурой MARK значение указателя кучи. Освобождается участок кучи от адреса, | ||
| + | |||
| + | Функция SEG. | ||
| + | |||
| + | Возвращает значение типа WORD, содержащее сегмент адреса указанного объекта. Вызов: | ||
| + | |||
| + | SEG ( X ) | ||
| + | |||
| + | Здесь X – выражение любого типа или имя процедуры. | ||
| + | |||
| + | Функция SIZEOF. | ||
| + | |||
| + | Возвращает длину в байтах внутреннего представления указанного объекта. Вызов: | ||
| + | |||
| + | SIZEOF ( X ) | ||
| + | |||
| + | Здесь X – имя переменной, | ||