Студопедия
Новини освіти і науки:
МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах


РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання


ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ"


ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ


Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків


Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні


Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах


Гендерна антидискримінаційна експертиза може зробити нас моральними рабами


ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ


ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів



Покажчики

Begin

Begin

Begin

Begin

Begin

assign(f,'showfile.pas');

reset(f);

while not eof(f) do

while not eoln(f) do

read(f,c);

write(c);

end;

readln(f);

writeln;

end;

close(f);

readln;

end.

3. Запис даних у файл

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

rewrite(TxtFile: text);

До її виклику файлова змінна повинна бути прив'язана до імені файлу на диску за допомогою assign. Якщо файл не існував, то rewrite створить його, якщо існував, той уміст буде стерто. У будь-якому випадку файл буде порожнім, а покажчик запису розташується на початку файлу.

Для запису використовуються процедури

write(TxtFile: text, p1: type1, p2: type2, ... pN: typeN);

writeln(TxtFile: text, p1: type1, p2: type2, ... p: type);

Тут як параметри p1, p2, ... p можна використовувати не тільки змінні, але і вирази: числових типів, рядкові, символьні і логічні (boolean). На відміну від write, writeln після запису у файл значень p1, p2, ... p переводить покажчик запису на початок нового рядка; writeln з одним параметром (текстовий файл) лише переводить покажчик на новий рядок.

Так само як і у випадку з читанням з файлу, після того як усі дані записані файл потрібно закрити за допомогою close.

 

Приклад 2 (запис у файл). Нехай даний довільний текстовий файл, потрібно одержати інший файл, у кожнім рядку якого записана довжина відповідної рядка вихідного файлу:

program WriteLength;

var f1,f2: text;

s: string;

assign(f1,'writelen.pas'); reset(f1);

assign(f2,'result.txt'); rewrite(f2);

while not eof(f1) do

readln(f1,s);

writeln(f2,length(s));

end;

close(f1); close(f2);

end.

 

Ще один спосіб запису — це відкриття для додавання інформації в кінець файлу. Для цього використовується процедура

append(TxtFile: text);

Якщо файл відкритий за допомогою append, то весь його вміст зберігається. При завершенні дописування в кінець файлу його також варто закрити за допомогою close.

 

Двійкові файли

Двійковий файл являє собою послідовність однакових елементів, записаних на диску. На відміну від текстових файлів, у двійкових немає розбивки на рядки, файл нагадує масив, з тією лише різницею, що доступ до елементів може бути не тільки послідовним. Для того, щоб визначити, чи досягнуть кінець файлу, як і раніше використовується функція eof. Функція eoln, мабуть, тут незастосовна.

Для всіх обговорюваних нижче файлів можна виконувати ті ж процедури відкриття, закриття і прив'язки, що і для текстових: Append, Assign, Close, Reset, Rewrite. Крім того, з'являється процедура Truncate(var f: file), що знищує весь уміст файлу, що знаходиться після поточного покажчика читання.

Двійкові файли будемо поділяти на типізовані і нетипізовані.

1. Типізовані файли

Файли цього виду складаються з елементів однакового типу, тобто в них не можна записувати (чи читати) значення змінних різних типів, на відміну від текстових файлів.

Оголошують типізовані файли так:

var f: file of тип_елемента;

Як тип елемента можна використовувати як прості типи, так і структуровані (масиви, записи і т.п.).

2. Нетипізовані файли

Крім визначених в авторській версії мови типізованих файлів і текстових файлів, Turbo Pascal містить поняття нетипізованих файлів чи файлів без типу. Відповідні змінні описуються за допомогою службового слова file (без of), наприклад:

var

Data:file;

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

Нетипізовані файли відкриваються тими ж процедурами, що і звичайні і текстові файли, - Reset і Rewrite, але для нетипізованих файлів другим параметром цих процедур повинний бути заданий розмір запису (елемента файлу), наприклад:

Assign(Data, 'MYDATA.DTA') ; Reset(Data,200) ;

Розмір запису задається в байтах; якщо другий параметр опущений, то передбачається розмір у 128 байтів. При цьому варто враховувати дві обставини. По-перше, для забезпечення максимальної швидкості обміну довжина запису повинна бути кратною розміру фізичного сектора диска - 512 байтів. З іншого боку, потрібно пам'ятати, що загальний розмір файлу може не бути кратний обраному розміру запису (останній запис може бути неповним). Для того, щоб гарантовано забезпечити повне читання усього файлу, потрібно установити розмір запису рівним 1.

Для організації обмінів з нетипізованими файлами в мові Turbo Pascal призначені дві стандартні процедури:

BlockRead

BlockWrite

Як робочий буфер для обмінів використовується змінна, котру необхідно описати в програмі і розмір якої не повинний бути менше розміру запису, встановленого в параметрах Reset чи Rewrite. Ім'я цієї змінної вказується у виклику процедури BlockRead (BlockWrite). Заголовок першої процедури описується так:

BlockRead ( var F:file,- var Buf; Count:word )

BlockRead ( var F:file; var Buf; Count:word; var Result:word)

Тут F - ім'я нетипізованого файлу, з якого відбувається читання; Buf - змінна-буфер (цей параметр передається як нетипізований); Count - число записів, що читаються за один виклик. Крім цього, BlockRead може містити ще один параметр - Result, у який розташовуєтьс число фактично прочитаних записів. Змінна F повинна бути описана як нетипізований файл, зв'язана з конкретним фізичним диском процедурою Assign; файл повинний бути відкритий процедурою Reset.

При виконанні цієї процедури записи, що читаються з F розташовуються в опертивній пам’яті, починаючи з першого байта області, яку займає змінна Buf.

Аналогічно описується стандартна процедура BlockWrite:

BlockWrite ( var F:file,- var Buf; Count:word )

BlockWrite ( var F:file,- var Buf; Count:word; var Result:word )

Зміст параметрів той же, що й у параметрів попередньої процедури, з тією лише різницею, що файл F повинний бути підготовлений для запису процедурою Rewrite. Уміст перемінної Buf цілком розміщується у файл F, починаючи з поточного запису.

В обох процедурах потрібно стежити за тим, щоб розмір змінної-буфера Buf був рівним RecSize*Count, де RecSize -розмір запису, зазначеної в процедурах Reset чи Rewrite, Count - число записів,що читаються (записуються) , тобто значення параметра.

Якщо при записі у файл процедурою BlockWrite на диску не виявиться вільного простору чи при читанні з файлу процедурою BlockRead розмір буфера виявиться менше зазначеного вище добутку, то відбудеться наступне: якщо останній параметр Result у цих викликах не заданий, то виникне помилка введення-виведення; якщо параметр Result заданий, то помилка не буде зафіксована, а після виконання процедури його значення не буде збігатися зі значенням параметра Count. Останню обставину можна перевірити, порівнявши два зазначених значення.

Приведемо простий приклад використання нетипізованих файлів для копіювання інформації, узятий з підсистеми оперативної допомоги Turbo Pascal. У наступній програмі використовуються стандартні функції ParamCount і ParamStr, що обробляють строкові параметри, передані програмі при її запуску з командного рядка чи через альтернативу Run/Parameters . .. інтегрованого середовища. Функція ParamCount повертає загальне число переданих параметрів, а функція ParamStr - рядок, що містить параметр із зазначеним порядковим номером.

program FileCopy;

{Копіювання файлу; файл-джерело і файл-приймач}

{задаються у виді строкових параметрів програми. }

{Спрощений варіант (без контролю помилок) }

const RecSize = 512; {розмір буфера обміну)

var

FileIn,

FileOut : file; { копіюємо FileIn -> FileOut }

NumRead, { число фактично лічених } NumWritten: Word; { і фактично записаних записів }

Buf: array[l..RecSize] of char; {буфер обміну }

begin

if ParamCount<2 then Halt;{ перевірка числа параметрів }

{ Відкриваємо файл-джерело )

Assign(FileIn,ParamStr(l));

{$I-}

Reset(FileIn,l);

{$I+}

if IOResult <> 0 then begin

Writeln('Файл-джерело не знайдене'); Halt end;

{ Відкриваємо файл-приймач )

Assign(FileOut,ParamStr(2));

Rewrite(FileOut,1);

WriteLn('KonnpyeM ',ParamStr(l),' -> ,ParamStr(2));

{ Цикл копіювання }

repeat

BlockRead(FileIn,Buf,RecSize,NumRead);

BlockWrite(FileOut,Buf,NumRead,NumWritten);

until(NumRead = 0) or (NumWritten <> NumRead);

WriteLn('Копіювання закінчене');

{ Закриваємо файли }

Close(FileIn);

Close(FileOut)

end.

На закінчення помітимо, що після кожного виклику процедур BlockRead і BlockWrite поточний покажчик файлу зміщається на число записів, що фактично брали участь в обміні. Додатково допускається використання процедур і функцій Seek, FileSize і FilePos для організації доступу до будь-якого запису нетипізованого файлу.


Статичні і динамічні змінні

Дотепер ми мали справу з так називаними статичними даними і статичними змінними. Такі змінні з'являються на початку програми (у розділі описів) і існують до завершення її роботи. Відповідно, пам'ять для змісту цих змінних виділяється при запуску програми і залишається зайнятої увесь час, поки програма працює.

Очевидно, що це не самий раціональний спосіб використання пам'яті комп'ютера. Наприклад, деяка змінна може використовуватися тільки один раз у єдиному операторі великої програми, однак пам'ять, виділена під цю змінну, залишається зайнята увесь час, поки працює програма. А чи не можна зробити так, щоб пам'ять для такої змінної виділялася в момент, коли змінна починає використовуватися, і звільнялася відразу ж по завершенні її використання? І щоб цю пам'ять відразу можна було виділити для інших даних? Виявляється, це цілком реально і саме для цієї мети в Turbo Pascal уведене поняття динамічної пам'яті. Динамічна пам'ять, відома також як купа, розглядається в TurboPascal як масив байтів.

Правда, при динамічному розміщенні до даних не удасться звертатися по іменах, як до статичних даних, з якими ми дотепер мали справу. Крім того, кількість і тип динамічно розташовуваних даних заздалегідь невідомі. Динамічна пам'ять виділяється для даних (і звільняється) у ході роботи програми. Для керування динамічною пам'яттю Turbo Pascal надає гнучкий засіб, відомий як покажчики.

Ми вже знаємо, що оперативна пам'ять комп'ютера — це множина кромірок, кожна з яких призначена для збереження одного байта інформації, і кожна має власну адресу, по якій до цієї комірки можна звернутися. Отож, покажчик — це змінна, що об’явлена в розділі описів програми, значення якої і являє собою адресу одного байта пам'яті.

Покажчики, використовувані в Turbo Pascal, бувають типізовані і нетипізовані. Якщо нетипізований покажчик — це змінна, що містить адресу даних довільного типу, то типізований покажчик містить адресу даних, тип яких обумовлюється при оголошенні даного покажчика.

Нетипізовані покажчики описуються так:

var

pp : pointer;

де POINTER— стандартний тип даних;

PP — змінна, що містить адресу пам'яті, за якою можуть зберігатися дані довільного типу.

Що стосується типізованих покажчиків, то їх оголошення в програмах на Turbo Pascal виглядають так:

var

px : ^char;

py : ^integer;

У цьому прикладі описані два типізованих покажчики: PX і PY. значення цих змінних являють собою адреси в оперативній пам'яті, по яких містяться дані типу Char і Integer відповідно. Неважко помітити, що опис типізованого покажчика відрізняється від опису статичної змінний того ж типу тільки тим, що у випадку покажчика перед типом присутній символ "^".

Підсумуємо: коли потрібно скористатися динамічною пам'яттю, у розділі описів з'являється не сама змінна, а покажчик (чи посилання) на неї. У цьому випадку покажчик являє собою звичайну змінну, а змінна, на яку він посилається, — динамічну. При цьому, якщо у виразі повинний бути присутнім покажчик, використовується ідентифікатор, оголошений у розділі описів. От так: PX. Однак, якщо у виразі повинна фігурувати динамічна змінна, на яку посилається покажчик, ідентифікатор покажчика доповнюється символом "^". Така дія називається розіменуванням. Наприклад, PX^. Щоб навчитися користатися покажчиками, абсолютно необхідно засвоїти те, про що йшла мова в даному абзаці.

Ще приклад:

type

DatePointer = ^Date;

Date=record

year : 1900..2100;

month : 1..12;

day : 1..31;

next : DatePointer

end;

var

pd : DatePointer;

Тут оголошений тип DatePointer, що представляє собою покажчик на тип Date, що описує запис. Уважний читач зверне увагу, що тип DatePointer описаний до типу Date, на який він посилається. У той же час одне з полів запису Date належить типу DatePointer. У цілому, у Turbo Pascal не допускається посилатися на ще не описані типи, однак у даному випадку (досить частому, коли приходиться мати справа з покажчиками як ні розташовуй опису, усе одно посилання на ще не описаний тип не уникнути. Тому єдине виключення зроблене для покажчиків: тип покажчика на динамічні дані може бути оголошений до опису самих даних.

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

var

px, py : ^char;pz : ^integer;

У цьому випадку операція присвоювання припустима для покажчиків PX і РУ:

px : =py;

Однак зовсім неприпустимими виявляться оператори:

px : =pz;

чи

pz : =py;

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

var

px : ^char;

py : ^integer;

pz : pointer;

Для цих змінних припустимі оператори присвоювання:

px := pz; py := pz;

pz :=py; pz := px;

Неважко прийти до висновку, що нетипізовані покажчики — дуже зручний засіб перетворення типів даних.


Читайте також:

  1. Покажчики
  2. Сигнальні покажчики та знаки




Переглядів: 1344

<== попередня сторінка | наступна сторінка ==>
Обробка помилок введення-виведення | Стан покажчика

Не знайшли потрібну інформацію? Скористайтесь пошуком google:

  

© studopedia.com.ua При використанні або копіюванні матеріалів пряме посилання на сайт обов'язкове.


Генерація сторінки за: 0.05 сек.