Теми рефератів
Авіація та космонавтика Банківська справа Безпека життєдіяльності Біографії Біологія Біологія і хімія Біржова справа Ботаніка та сільське гос-во Бухгалтерський облік і аудит Військова кафедра Географія
Геодезія Геологія Держава та право Журналістика Видавнича справа та поліграфія Іноземна мова Інформатика Інформатика, програмування Історія Історія техніки
Комунікації і зв'язок Краєзнавство та етнографія Короткий зміст творів Кулінарія Культура та мистецтво Культурологія Зарубіжна література Російська мова Маркетинг Математика Медицина, здоров'я Медичні науки Міжнародні відносини Менеджмент Москвоведение Музика Податки, оподаткування Наука і техніка Решта реферати Педагогіка Політологія Право Право, юриспруденція Промисловість, виробництво Психологія Педагогіка Радіоелектроніка Реклама Релігія і міфологія Сексологія Соціологія Будівництво Митна система Технологія Транспорт Фізика Фізкультура і спорт Філософія Фінансові науки Хімія Екологія Економіка Економіко-математичне моделювання Етика Юриспруденція Мовознавство Мовознавство, філологія Контакти
Українські реферати та твори » Информатика, программирование » Опис покажчиків

Реферат Опис покажчиків

жна передавати значення тільки між покажчиками, пов'язаними з одним і тим же типом даних. Якщо, наприклад,


var

p1, p2: ^ integer;

р3: ^ real;

рр: pointer;

то присвоювання

р1: = р2;

цілком припустимо, в то час як

р1: = р3;

заборонено, оскільки Р1 і Р3 вказують на різні типи даних. Це обмеження, проте, не поширюється на нетипізовані покажчики, тому ми могли б записати

pp: = р3;

р1: = рр;

і тим самим досягти потрібного результату.

Читач має право задати питання, чи варто було вводити обмеження і тут же давати кошти для їх обходу. Вся справа в тому, що будь-яке обмеження, з одного боку, вводиться для підвищення надійності програм, а з іншого - зменшує потужність мови, робить його менш придатним для якихось застосувань. У Турбо Паскалі нечисленні виключення у відношенні типів даних надають мові необхідну гнучкість, але їх використання вимагає від програміста додаткових зусиль і таким чином свідчить про цілком усвідомленому дії.


Використання покажчиків

Підіб'ємо деякі підсумки. Отже, динамічна пам'ять складає 200 ... 300 Кбайт або більше, її початок зберігається в змінної HEAPORG, a кінець відповідає адресі змінної HEAPEND. Поточний адресу вільної ділянки динамічної пам'яті зберігається в покажчику HEAPPTR.

Подивимося, як можна використовувати динамічну пам'ять для розміщення великих масивів даних. Нехай, наприклад, потрібно забезпечити доступ до елементів прямокутної матриці 100х200 типу EXTENDED. Для размщеенія такого масиву вимагається пам'ять 200 000 байт (100 * 200 * 10). Здавалося б, цю проблему можна вирішити наступним чином:

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, j]);

end.

Тепер до будь-якого елементу новоствореного динамічного масиву можна звернутися за адресою, наприклад:

PtrArr [1,1] ^ : = 0;

if PtrArr [i, j * 2] ^> 1 then

Згадаймо, однак, що довжина внутрішнього подання покажчика становить 4 байти, тому для розміщення масиву PTRARR буде потрібно 100 * 200 * 4 = 80000 байт, що перевищує розмір сегмента даних (65536 байт), доступний, як уже зазначалося, програмі для статичного розміщення даних. Виходом з положення могла б послужити адресна арифметика, тобто арифметика над покажчиками, тому що в цьому випадку можна було б відмовитися від створення масиву покажчиків PTRARR і обчислювати адресу будь-якого елементу прямокутної матриці безпосередньо перед зверненням до нього. Однак в Турбо Паскалі над покажчиками не визначені жодні операції, крім операцій привласнення і відносини.

Тим не менш, вирішити зазначену задачу таки можна. Як ми вже знаємо, будь покажчик складається з двох слів типу WORD, в яких зберігаються сегмент і зсув. У Турбо Паскалі визначені дві вбудовані функції типу WORD, що дозволяють одержати вміст цих слів:

SEG (X) - повертає сегментну частина адреси;

OFS (X) - повертає зсув.

Аргументом Х при зверненні до цих функцій може служити будь-яка змінна, в тому числі і та, на яку вказує покажчик. Наприклад, якщо маємо

var

р: ^ real;

begin

new (p);

p ^: = 3.14;

end

то функція SEG (P) поверне сегментну частина адреси, за якою розташовується 4-байтним покажчик Р, в той час як SEG (P ^) - сегмент 6-байтного ділянки купи, в якому зберігається число 3.14.

З іншого боку, з допомогою вбудованої функції PTR (SEG, OFS: WORD): POINTER можна створити значення покажчика, сумісний з покажчиками будь-якого типу. Таким чином, можлива така послідовність дій. Спочатку процедурою GETMEM з купи забираються кілька фрагментів відповідної довжини (нагадаю, що за одне звернення до процедурі можна зарезервувати не більше 65521 байт динамічної пам'яті). Для рас сматривать прикладу зручно резервувати фрагменти такої довжини щоб у них могли, наприклад, розміститися рядки прямокутної матриці, тобто

200 * 10 = 2000 байт.

Початок кожного фрагмента, тобто фактично початок розміщення в пам'яті кожного рядка, запам'ятовується в масиві PTRSTR, що складається з 100 вказівників. Тепер для доступу до будь елементу рядка потрібно обчислити зміщення цього елемента від початку рядка і сформувати відповідний покажчик:

var

i, j: integer;

PtrStr: array [1 .. 100] of pointer;

pr: ^ real;

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 pr ^> 1 then

end

Оскільки оператор обчислення адреси PR: = PTR ... буде, судячи з усього, використовуватися в програмі неодноразово, корисно ввести допоміжну функцію GETR, повертаючу значення елемента матриці, і процедуру PUTR, що встановлює нове значення елемента. Кожна з них, у свою чергу, звертається до функції ADDRR для обчислення адреси. Нижче наводиться програма, що створює в пам'яті матрицю з NxM випадкових чисел і обчислює їх середнє значення.

program Primer1;

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);

{Поміщає в змінну, адреса якої має сегмент i

зсув j, речовий значення x}

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/(N * M): 12:10)

end. {Main}

У розглянутому прикладі передбачається, що кожен рядок розміщується в купі, починаючи з кордону параграфа, і зсув для кожного покажчика PTRSTR дорівнює нулю. В Насправді при послідовних зверненнях до процедури GETMEM початок чергового фрагмента слід відразу за кінцем попереднього і може не потрапити на кордон сегмента. В результаті, при розміщенні фрагментів максимальної довжини (65521 байт) може виникнути переповнення при обчисленні зміщення останнього байта.



Предыдущая страницаСтраница 2 из 2

Друкувати реферат
Замовити реферат
Товары
загрузка...
Наверх Зворотнiй зв'язок