Rekordok és file-kezelés
31.
Írjunk programot, mely bekér néhány gépkocsi adatát egy végjelig (pl.: - ),
majd gyártási éve szerint csökkenő sorrendben kiírja az összes adatot a
képernyőre. A gépkocsik adatai: gyártó, típus, rendszám, szín, gyártási év és
érvényes-e a műszakija.
Gyakran előfordul, hogy az adatok nem
függetlenek, hanem egy-egy tárgy vagy személy különböző jellemzői. Ebben az
esetben az a célszerű, ha ezt adatszerkezetileg is együtt vannak. Több adat
együttes tárolására eddig csak a tömb volt használható. Ennek a mostani
felvetésben az a problémája, hogy csak azonos típusú adatokat lehet benne
tárolni. Új típusra lenne szükség, amelyben szöveget, számok különböző
típusait, logikai változókat tárolhatunk. Ennek a típusnak a neve: rekord (Record), deklarációját a Type vezeti be és a mezők leírása az
ezt követő End;-ig tart. A mezők
típusa bármilyen előzőleg ismert, vagy deklarált típus lehet, lehet akár Record is. A rekord egy mezőjére Recordnev.Mezonev formában hivatkozhatunk.
Megengedett az azonos típusú rekordok között a közvetlen értékadás is, valamint
képezhetünk rekordokból akár tömböt is. Ha egy rekord több mezejét akarjuk kezelni
egymás után, akkor a rekordazonosító többszöri kiírása helyett a With . . . Do minősítő utasítást (szerkezetet) is használhatjuk. Mivel több
mezőt szeretnénk kezelni a Do után,
ezért kötelező összetett utasítást írni, azaz szinte biztosan Begin . . . End;-el folytatódik a program.
Program Kocsik;
Uses NewDelay,
Crt, CrtPlus;
Const Max=100;
Type Kocsi=Record
Gyarto
:String[10];
Tipus :String[15];
Rendszam:String[8];
Szin :String[12];
GyEv :Integer;
Muszak :String[5];
End;
Var KocsiTomb:
Array[1..Max] Of Kocsi;
UKocsi: Kocsi;
Procedure Init;
Var I: Byte;
Begin
UKocsi.Gyarto
:= ’’;
UKocsi.Tipus
:= ’’;
UKocsi.Rendszam:= ’’;
UKocsi.Szin
:= ’’;
UKocsi.GyEv
:= 0;
UKocsi.Muszak
:= ’’;
For
I:= 1 To Max Do KocsiTomb[I]:= UKocsi;
End;
Procedure Adatbe;
Var I: Byte;
Begin
ClrScr;
I:= 0;
Repeat
Inc(I);
With KocsiTomb[I] Do
Begin
Write(’Kérem a ’,i:3,’. kocsi
gyártóját : ’);
ReadLn(Gyarto);
If
Gyarto<>’-’ Then
Begin
Write(’Kérem a ’,i:3,’. kocsi típusát : ’);
ReadLn(Tipus);
Write(’Kérem a ’,i:3,’. kocsi
rendszámát : ’);
ReadLn(Rendszam);
Write(’Kérem a ’,i:3,’. kocsi színét : ’);
ReadLn(Szin);
Write(’Kérem a ’,i:3,’. kocsi gyártási
évét : ’);
ReadLn(GyEv);
Write(’Van-e a ’,i:3,’. kocsinak műszakija : ’);
ReadLn(Muszak);
End;
End;
Until
KocsiTomb[I].Gyarto=’-’;
End;
Procedure Kepre;
Var I: Byte;
Begin
Szinek(0,15);
CrlScr;
WriteLn(’Gyártó’:10,’ ’,’Típus’:15,’
’,’Rendszám’:8,’ ’,’Szín’:12,’ ’,’Gyév’:12,’ ’,’Műszak’:5);
Szinek(0,7);
I:= 0;
While KocsiTomb[I].Gyarto<>’-’ Do
With
KocsiTomb[I] Do
Begin
WriteLn(Gyarto:10,’ ’,Tipus:15,’
’,Rendszam:8,’ ’,Szin:12,’ ’,GyEv:12,’ ’,Muszak:5);
Inc(I);
End;
Tunj;
Varj;
End;
Begin
TextMode(CO80);
Init;
Adatbe;
Kepre;
End.
32. Írjunk
programot, amely lemezen tudja tárolni a felhasználó nevét és lakhelyét. Indítás
után kiírja a tárolt adatokat, megkérdezi, hogy helyesek-e, ha nem, bekéri és
kimenti a helyes adatokat.
A legtöbb program több-kevesebb olyan adattal
dolgozik, amely minden futtatáshoz szükséges, esetleg a futtatások alkalmával
megváltozik, de a legközelebbi használatkor a legutóbbi állapotoknak megfelelően
kell rendelkezésre állni. A programnak gondoskodni kell tehát az adatoknak
lemezre való mentéséről. Ennek alapjaival ismerkedünk meg ennek a programnak a
kapcsán. A pascal programok lemezes állományba menthetik az adatokat (és
természetesen onnan be is olvashatják). A lemezes állományok vagy file-ok három
csoportját tudja kezelni a pascal: szöveges állományok, tipizált állományok és
típus nélküli állományok. A szöveges állományok ASCII karaktereket
tartalmaznak, sorokra tagolódnak, melyeket soremelés, kocsi-vissza karakterek
választanak el egymástól, írni és olvasni soronként lehet. A tipizált állományokban
általában rekordok találhatók, bennük minden rekordnak ugyanannyi byte a
hossza, a rekordokon mozoghatunk, rekordokat írhatunk és olvashatunk. A típus
nélküli állományok, vagy bináris file-ok, változó hosszúságú írás és olvasást
engedélyez, de a kiolvasott adatok helyes értelmezése a program(ozó) felelőssége.
Feladatunk legegyszerűbben tipizált file segítségével oldható meg. Az FNev logikai file-név, egy személyekből
álló file-t jelent. A DNev a file
OS-beli neve, melyet teljesen konkrétan értékadással le kell írni. A
főprogramnak ez az első sora. A név tetszőleges lehet, csak az OS által
támasztott követelményeknek kell megfelelnie. A program első futtatáskor még
biztosan nem tudja teljesíteni a specifikáció feltételeit, hiszen a nevet
tartalmazó file-nak valamikor létre kell jönni. Ezért a program első változata
csak a kimentést tartalmazza. A file-kezelés lépéseit a Lemezre eljárásban figyelhetjük meg. Első lépésként a logikai és a
fizikai file-neveket egymáshoz kell rendelni. Ezt hajtja végre az Assign eljárás. Ettől kezdve minden
utasítást a logikai file-névre adunk ki, de az a fizikai állományon fog
végrehajtódni. A file-t kétféleképpen lehet megnyitni: írásra és olvasásra.
Írásra a ReWrite-tal kell megnyitni, ami egyúttal a file teljes újra építését
is jelenti, azaz, ha létezett az eljárás meghívása előtt, akkor teljesen elvész
a régi tartalom. Lényegében így hozzuk létre az új file-t. A másik megnyitás a Reset, amely után a file-t olvashatjuk és
írhatjuk is. Ekkor a régi tartalom megmarad, mármint azok a rekordok, amelyeket
nem írunk fölül. Ez a második programlistában láthatjuk, a Lemezrol függvényben. Annak érdekében, hogy a file tartalma el ne
vesszen, az adatkezelés után, de legkésőbben a program leállása előtt zárni
kell. Ezt végzi a Close eljárás. A Write eljárás alkalmazása jelent még itt
újdonságot. Eddig csak a képernyőre írásra használtuk. Ha a Write-ot úgy hívjuk meg, hogy első
paramétere egy logikai file-név, akkor nem a képernyőre, hanem a megfelelő
file-ba ír. Szöveges állománynál a Write
helyett WritLln-t kell használni, itt
a tipizált állománynál viszont csak a Write
használható.
Program Nevem;
Uses NewDelay,
Crt, CrtPlus;
Type Szemely=
Record
Neve: String[30];
Lakhelye: String[40];
End;
Var En: Szemely;
FNev:
File Of Szemely;
DNev: String;
Procedure Adatbe;
Begin
Szinek(0,7);
ClrScr;
Write('Kérem a személy nevét : '); ReadLn(En.Neve);
Write('Kérem a személy lakhelyét: ');
ReadLn(En.Lakhelye);
End;
Procedure Lemezre;
Begin
Assign(FNev,DNev); ReWrite(FNev);
Write(FNev,En);
Close(FNev);
End;
Begin
TextMode(CO80);
DNev:= 'ne.vem';
Adatbe;
Lemezre;
End.
A második, teljes listában természetesen a Lemezrol tartogat meglepetéseket. Az
első mindjárt az, hogy nem eljárás, hanem függvény logikai visszaadott
értékkel. Ez most kétszeresen is indokolt. Egyrészt nem biztos, hogy file amit
olvasni kell az egyáltalán létezik-e, másrészt nem biztos, hogy a benne lévő
adat megfelelő-e. Mindkettőre logikai értékkel válaszolhatunk. Így a két
vizsgálatot egyetlen függvény visszaadott értékében kifejezhetjük. Az első az
igazán érdekes, vajon mi van akkor, ha az adatot tartalmazó állomány nem is
létezik, mert pl. valaki letörölte. Hát bizony kellemetlen lenne, ha emiatt a
program nem lenne futtatható, mert Run-time error-ral megállna. A futás idejű
hibák egy részének kezelésére alkalmas az IOResult
hibakezelő függvény. Pontosan az input-output eljárások meghíváskor fellépő
hibák kezelhetők vele. Ha értéke nem nulla meghíváskor, akkor az érték a hiba
jellegére utal. Ahhoz, hogy a hiba létrejöttekor a program le ne álljon, még
egy dolgot tenni kell. A lehetséges hibaforrást (ez esetben a Reset eljárást)
körbe kell venni fordítási direktívákkal, olyanokkal, amely az input-output
hibafigyelő gépi rutinokat kikapcsolja, majd visszakapcsolja. A {$I-}
kikapcsol, a {I$+} bekapcsol. Viszont a következő utasításban a hibakezelő
függvényt kell lekezelni, különben értéke elvész. Ha tehát a nem létező file-t
olvasásra szeretnénk megnyitni, akkor az IOResult
értéke nem lesz nulla. Ekkor nyilván a tartalma sem egyezhet meg a felhasználó
nevével. Ezért a Lemezrol függvény False értéket kapja és Exit-el befejeződik.
Program Nevem;
Uses NewDelay,
Crt, CrtPlus;
Type Szemely=
Record
Neve:String[30];
Lakhelye:String[40];
End;
Var En: szemely;
FNev: File
Of Szemely;
DNev: String;
Function Lemezrol:
Boolean;
Var Ch: Char;
Begin
Szinek(0,15);
ClrScr;
Assign(FNev,DNev);{$I-}Reset(FNev);{$I+}
If
IOResult<>0 Then
Begin
Lemezrol:= False;
Exit;
End;
Read(FNev,En);
Close(FNev);
WriteLn('A felhasználó adatai:');
WriteLn;
Szinek(0,7);
WriteLn('Neve : ',En.Neve);
WriteLn('Lakhelye: ',En.Lakhelye);
WriteLn;
Szinek(0,15);
WriteLn('Helyesek az adatok (I/N)?');
Tunj;
Repeat
Ch:= ReadKey;
Ch:= UpCase(ch);
Until
Ch In ['I','N'];
Lemezrol:= Ch='I';
End;
Procedure Adatbe;
Begin
WriteXY(1,8,'Kérem a személy nevét : '); ReadLn(En.Neve);
WriteXY(1,9,'Kérem a személy lakhelyét: ');
ReadLn(En.Lakhelye);
End;
Procedure Lemezre;
Begin
Assign(FNev,DNev); ReWrite(FNev);
Write(FNev,En);
Close(FNev);
End;
Begin
DNev:= 'ne.vem';
If
Not lemezrol Then
Begin
Adatbe;
Lemezre;
End;
End.
Ha a file létezik, akkor tartalmát Read-el kiolvassa. Aztán tér rá annak
megkérdezésére, hogy jó-e a tárolt adat. A válasz kiértékelésekor használjuk az
UpCase függvényt, amely a betűkhöz a
nagybetűs alakját rendeli, ezért elegendő csak nagybetűs I és N-nel a logikai
beállítást megtenni. Végül is, így a főprogramban egyetlen Lemezrol függvényhívással kezelhetjük mindkét, előzőleg említett
logikai értékkel bíró esetet.
33.
Írjunk programot, amely tanulók adatait tudja nyilvántartani. Legyen lehetőség
az adatok felvételére (név, születési év, osztálya, lakása és tanulmányi
átlaga), azok javitására. A program egyszerre tudjon kezelni 50 tanuló adatát,
melyet lemezes állományban tárol. Legyen lehetőség a következő lekérdezésekre:
névsor szerint, korok szerint, lakhely szerint, átlag szerint és tudjon
osztályátlagot számítani.
A program megírásához gyakorlatilag mindent
megtanultunk az eddigi programok kapcsán. Ez a program annyiban lesz új, hogy
ilyen komplex program megírására eddig még nem vállalkoztunk. A program
használata közben szükség lesz arra, hogy egy esemény bekövetkezéséről a gép
informáljon minket (lemezműveletek), illetve eldöntendő kérdést tegyen fel a
program (pl. adatmentéssel kapcsolatban). Ilyen rutin illetve függvény más
programban is hasznos lehet, ezért ezeket a CrtPlus-ba helyezzük.
Unit
CrtPlus;
Interface
Uses NewDelay,
Crt;
. . .
Procedure Ablak(HSz,KSz,Bfx,Bfy,Jax,Jay:
Byte; Arny: Boolean; C: String);
Procedure
Uzenet(HSz,KSz: Byte; Sz: String);
Function
Kerdezo(HSz,KSz: Byte; Sz: String): Boolean;
. . .
Implementation
. . .
Procedure
Uzenet(HSz,KSz: Byte; Sz: String);
Var
Bfx,Bfy,Jax,Jay: Byte;
LKep: Scr;
N: Byte;
Begin
N:= Length(Sz);
If
N<10 then N:= 10;
Bfx:= 40-Round(N/2)-2;
Bfy:= 11;
Jax:= 40+Round(N/2)+1;
Jay:= 13;
LKep:= BKep;
Ablak(HSz,KSz,Bfx,Bfy,Jax,Jay,True,’Info’);
Writexy(40-Round(Length(Sz)/2,12,Sz);
Tunj;
Varj;
BKep:= LKep;
End;
Function
Kerdezo(HSz,KSz: Byte; Sz: String): Boolean;
Var
Bfx,Bfy,Jax,Jay: Byte;
LKep: Scr;
N: Byte;
Ch: Char;
Begin
N:= Length(Sz);
If
N<20 Then N:= 20;
Bfx:= 40-Round(N/2)-2;
Bfy:= 11;
Jax:= 40+round(N/2)+1;
Jay:= 13;
LKep:= BKep;
Ablak(HSz,KSz,Bfx,Bfy,Jax,Jay,True,’Válaszoljon
(I/N)’);
Writexy(40-Round(Length(Sz)/2,12,Sz);
Tunj;
Repeat
Ch:= ReadKey;
Ch:= UpCase(Ch);
Until
Ch In [’I’,’N’];
Kerdezo:= Ch=’I’;
BKep:= LKep;
End;
. . .
End.
Gyakran előfordul, hogy a programok által kezelt
objektumok közül választanunk kell azért, hogy a program a továbbiakban a
kiválasztott elemen végezzen bizonyos műveletek. Legtöbb esetben az elemek
lineárisan rendezett tömbökben helyezkedik el. A választást megkönnyíthetjük
azáltal, hogy az objektumok (legtöbbször rekordok) kulcsmezőit egy
string-listába helyezzük, majd egy ablakban megmutatjuk és a listából a
kurzorvezérlő billentyükkel választhatunk. A választás eredménye (visszaadott
értéke) a kiválasztott elem sorszáma. A most vázolt megoldás szintén elég
általános, a megvalósító függvényt a CrtPlus-ban helyezzük el. A listázandó stringeket
a Tomb[1..Max] String tömbbe kell
előzőleg betölteni.
Unit CrtPlus;
Interface
Uses NewDelay,
Crt;
. . .
Function
Menu(Bfx,Bfy,Sh,Ss,As: Byte): Byte;
Function
Listazo(HSz,KSz,VSz,Bfx,Bfy,Sh,Ss,Ls,As: Integer;
Arny: Boolean; C: String): Integer;
const Max=500;
Var
. . .
Tomb: Array[1..Max]
Of String[80];
VCh: Char;
. . .
Implementation
. . .
Function
Listazo(HSz,KSz,Vsz,Bfx,Bfy,Sh,Ss,Ls,As: Integer;
Arny: Boolean; C: String): Integer;
Var
Ki,Ai,Vi,Aks: Integer;
Ch: Char;
Procedure
Kiir;
Var J, Ay: Integer;
Begin
Ki:= Round(As-Ls/2); Vi:= Round(As+Ls/2)-1;
If
Ki<=0 Then Inc(Ki,Ss); If Vi>Ss Then Dec(Vi,Ss);
Window(Bfx+2,Bfy+1,Bfx+Sh-2,Bfy+Ls);
ClrScr;
If
Vi>Ki Then For J:= Ki To Vi Do WriteXY(1,1+J-ki, Copy(Tomb[J],1,Sh-1))
Else
Begin
If
As<=Ss-Ls/2 Then Inc(Ki);
For
J:= Ki To Ss Do WriteXY(1,1+J-Ki,Copy(Tomb[J],1,Sh-1));
Ay:= WhereY;
For
J:= 1 To Vi Do
Begin
Inc(Ay); WriteXY(1,Ay,Copy(Tomb[J],1,Sh-1)) End;
End;
Window(1,1,80,25);
Tunj;
End;
Begin
If
Ls>Ss Then Ls:= Ss; If Ls<3 Then Ls:= 3;
If
Not Odd(Ls) Then Dec(Ls);
If
Ls>21 Then Ls:= 21;
If
Bfy+Ls+1>24 Then Repeat Dec(Bfy) Until Bfy+Ls+1<25;
Aks:= Bfy+Round(Ls/2);
Ablak(HSz,KSz,Bfx,Bfy,Bfx+Sh,Bfy+Ls+1,Arny,C);
Kiir;
Szinez(VSz,KSz,Bfx+2,Aks,Sh-3);
Repeat
Ch:= ReadKey;
If
(Ch=#0) And KeyPressed Then
Begin
Ch:=
ReadKey;
If
Ch In [#71,#72,#73,#79,#80,#81] Then Szinez(HSz,KSz,Bfx+2,Aks,Sh-3);
Case
Ch Of
#71: As:=1;
#72: Begin
Dec(Ki);
Dec(As); Dec(Vi);
If
Ki<1 Then Ki:= Ss;
If As<1 then As:= Ss;
If Vi<1 Then Vi:= Ss;
End;
#73: Begin
Dec(Ki,Ls); Dec(As,Ls); Dec(Vi,Ls);
If Ki<1 Then Begin If Ki=0 Then Ki:= Ss Else Ki:= Ki+Ss+1 End;
If As<1 Then Begin If As=0 Then As:= Ss Else As:= As+Ss+1 End;
If Vi<1 Then Begin If Vi=0 Then Vi:= Ss Else Vi:= Vi+Ss+1 End;
End;
#79: As:= Ss;
#80: Begin
Inc(ki); Inc(As); Inc(Vi);
If Ki>Ss Then Ki:= 1;
If As>Ss Then As:= 1;
If
Vi>Ss Then Vi:= 1;
End;
#81: Begin
Inc(Ki,Ls); Inc(As,Ls); Inc(Vi,Ls);
If Ki>Ss Then Ki:=
Ki-Ss;
If As>Ss Then As:=
As-Ss;
If
Vi>Ss Then Vi:= Vi-Ss;
End;
End;
Kiir;
If
Ch In [#71,#72,#73,#79,#80,#81] Then Szinez(VSz,KSz,Bfx+2,Aks,Sh-3);
End;
Until
Ch In [#13,#27];
VCh:= Ch;
If
Ch=#27 Then Listazo:= 0 Else Listazo:= As;
End;
End.
A
Listazo függvény paraméterei:
HSz:
ablak háttérszín;
KSz:
ablak karakterszín;
VSz:
választósor háttérszíne;
Bfx:
az ablak bal felső sarka X koordinátája;
Bfy:
az ablak bal felső sarka Y koordinátája;
Sh:
sorok hossza;
Ss:
sorok száma;
Ls:
látható sorok száma;
As:
aktuális sorszám.
Ezek
után nézzük a Tanulok nevű program
listáját. Az egyes rutinok funkciói:
Init:
kezdő illetve üres értékek beállítása;
Lemezrol:
az adatállomány lemezről való betöltése, ha nem létezik létrehozása;
Lemezre:
adatállomány lemezre mentése;
Nevtolto:
a tanulónevek betöltése a Tomb[1..Max] tömbbe, a listázó függvény számára;
Javitás:
az adatok karbantartását végző eljárás;
Smake:
a minden tanulói adatot tartalmazó string tömb előállítása a listázó függvény
számára;
Nevszerint:
a tanulói adatok rendezése név szerint;
Korszerint:
a tanulói adatok rendezése kor szerint;
Lakszerint:
a tanulói adatok rendezése lakhely szerint;
Atlszerint:
a tanulói adatok rendezése átlag szerint;
Osztatlag:
osztályátlag kiszámítása;
Stati:
a statisztikai műveletek hívását végző rutin;
Program
Tanulok;
Uses NewDelay,
Crt,CrtPlus;
Const Amax=50;
Msor: Array[1..4]
Of String[15]=
(' Betöltés ',
' Tanuló adatai ',
' Lekérdezések ',
' Befejezés ');
Type Tanulo=Record
Nev: String[25];
Szul: Integer;
Oszt: String[3];
Lak: String[30];
Atl: Real;
End;
Var ATanulo,UTanulo:
Tanulo;
At: integer;
TTanulo: Array[1..Amax] Of Tanulo;
Mp: Byte;
I: Integer;
Adatbent, Adatvalt: Boolean;
FNev: File
Of Tanulo;
DNev: String;
Atlag: Real;
Procedure Init;
Begin
Adatbent:= False;
Mp:= 1; At:= 1;
With
UTanulo Do
Begin
Nev:= '-';
Szul:= 0;
Oszt:= '-';
Lak:= '-';
Atl:= 0;
End;
For
I:= 1 To Amax Do TTanulo[I]:= UTanulo;
DNev:= '11b.tan';
End;
Procedure Lemezrol;
Begin
If
Adatbent Then
Begin
Uzenet(5,15,'Az adatállomány már be van
töltve!');
Exit;
End;
Assign(FNev,DNev); {$I-}Reset(FNev);{$I+}
If
IOResult<>0 Then
Begin
ReWrite(fnev);
For
I:= 1 To Amax Do Write(FNev,TTanulo[I]);
End
Else
For
I:= 1 To Amax Do Read(FNev,TTanulo[I]);
Close(FNev);
Adatbent:= True;
Uzenet(5,15,'Az adatállomány betöltve!');
End;
Procedure Lemezre;
Begin
Assign(FNev,DNev); ReWrite(FNev);
For
I:= 1 To Amax Do Write(FNev,TTanulo[I]);
close(FNev);
Uzenet(5,15,'Az adatállomány kimentve!');
End;
Procedure Nevtolto;
Var S: String;
Begin
For
I:= 1 To Amax Do
Begin
Str(I,S);
If
I<10 Then S:= ' '+S;
Tomb[I]:= ' '+S+'.'+TTanulo[I].Nev;
End;
End;
Procedure Javitas;
Var S: String;
Sz,Kod :integer;
R: real;
Begin
If
Not Adatbent Then
Begin
Uzenet(5,15,'Nincs megnyitva
adatállomány!');
Exit;
End;
Szinek(1,0); ClrScr;
At:= Listazo(7,0,2,25,5,30,Amax,11,At,True,'Tanulók
névsora:');
If
VCh=#27 Then Exit;
Szinek(7,0); ClrScr;
ATanulo:= TTanulo[At];
Ablak(1,14,10,6,70,18,True,'A tanuló adatai:');
WriteXY(13, 8,'A tanuló neve.......:');
WriteXY(13,10,'Születési éve.......:');
WriteXY(13,12,'Osztálya............:');
WriteXY(13,14,'Lakhelye............:');
WriteXY(13,16,'Tanulmányi átlaga...:');
Szinek(0,14);
With
Atanulo Do
Begin
WriteXY(37,8,nev);
Str(Szul,S);
WriteXY(37,10,S);
WriteXY(37,12,Oszt);
WriteXY(37,14,Lak);
GoToXY(37,16);
Write(Atl:4:2);
End;
With
Atanulo Do
Begin
S:= Bevitel(7,0,37,8,25); If VCh<>#27 Then
Begin
Adatvalt:= True; Nev:= s End;
Repeat
S:= Bevitel(7,0,37,10,4); Val(S,Sz,Kod);
Until
(Kod=0) Or (VCh=#27);
If
VCh<>#27 Then Begin Adatvalt:= True; Szul:= Sz End;
S:= Bevitel(7,0,37,12,3);
If
VCh<>#27 Then Begin Adatvalt:= True; Oszt:= S End;
S:= Bevitel(7,0,37,14,30);
If
VCh<>#27 Then Begin Adatvalt:= True; Lak:= S End;
Repeat
S:= Bevitel(7,0,37,16,4); Val(S,R,Kod);
Until
(Kod=0) Or (VCh=#27);
If
VCh<>#27 Then Begin Adatvalt:= True; Atl:= R End;
End;
If
Adatvalt Then TTanulo[At]:= ATanulo;
End;
Procedure SMake;
Var Ws,W: String[80];
Begin
For
I:= 1 To Amax Do
Begin
Ws:= '';
Str(I,Ws);
If
Length(Ws)=1 Then Ws:= ' '+Ws;
Ws:= Ws+'.';
Ws:= Ws+TTanulo[I].Nev;
Ws:= Copy(Ws+' ',1,29);
Str(TTanulo[I].Szul,W);
Ws:= Ws+W;
Ws:= Copy(Ws+' ',1,34);
Ws:= Ws+TTanulo[I].Oszt;
Ws:= Copy(Ws+' ',1,38);
Ws:= Ws+TTanulo[I].Lak;
Ws:= Copy(Ws+' ',1,69);
Str(TTanulo[I].Atl:4:2,W);
Ws:= Ws+W;
Tomb[I]:= Ws;
End;
End;
Procedure Nevszerint;
Var I, J: Integer;
PTanulo: Tanulo;
Begin
For
I:= 1 To Amax-1 Do For J:= I+1 To Amax Do
If
TTanulo[I].Nev>TTanulo[J].Nev Then
Begin
PTanulo:= TTanulo[I];
TTanulo[I]:= TTanulo[J];
TTanulo[J]:= PTanulo;
Adatvalt:= True;
End;
While
TTanulo[1].Nev[1]='-' Do
Begin
For
J:= 1 To Amax-1 Do TTanulo[J]:= TTanulo[J+1];
TTanulo[Amax]:= UTanulo;
End;
SMake;
Listazo(7,0,2,1,3,77,Amax,19,1,True,'A
tanulók névsor szerint:');
End;
Procedure Korszerint;
Var I, J: Integer;
PTanulo: Tanulo;
Begin
For
I:= 1 To Amax-1 Do For J:= I+1 To Amax Do
If
TTanulo[I].Szul>TTanulo[J].Szul Then
Begin
PTanulo:= TTanulo[I];
TTanulo[I]:= TTanulo[J];
TTanulo[J]:= PTanulo;
Adatvalt:= True;
End;
While
TTanulo[1].Nev[1]='-' Do
Begin
For
J:= 1 To Amax-1 Do TTanulo[J]:= TTanulo[J+1];
TTanulo[Amax]:= UTanulo;
End;
SMake;
Listazo(7,0,2,1,3,77,Amax,19,1,True,'A
tanulók névsora koruk szerint:');
End;
Procedure Lakszerint;
Var I, J: Integer;
PTanulo: Tanulo;
Begin
For
I:= 1 To Amax-1 Do For J:= I+1 To Amax Do
If
TTanulo[I].Lak>TTanulo[J].Lak Then
Begin
PTanulo:= TTanulo[I];
TTanulo[I]:= TTanulo[J];
TTanulo[J]:= PTanulo;
Adatvalt:= True;
End;
While
TTanulo[1].Nev[1]='-' Do
Begin
For
J:= 1 To Amax-1 Do TTanulo[J]:= TTanulo[J+1];
TTanulo[Amax]:= UTanulo;
End;
SMake;
Listazo(7,0,2,1,3,77,amax,19,1,True,'A
tanulók névsora lakhely szerint:');
End;
Procedure Atlszerint;
Var I, J: Integer;
PTanulo: Tanulo;
Begin
For
I:= 1 To Amax-1 Do For J:= I+1 To Amax Do
If
TTanulo[I].Atl>TTanulo[J].Atl Then
Begin
PTanulo:= TTanulo[I];
TTanulo[I]:= TTanulo[J];
TTanulo[J]:= PTanulo;
Adatvalt:= True;
End;
While
TTanulo[1].Nev[1]='-' Do
Begin
For
J:= 1 To Amax-1 Do TTanulo[J]:= TTanulo[J+1];
TTanulo[Amax]:= UTanulo;
End;
SMake;
Listazo(7,0,2,1,3,77,Amax,19,1,True,'A tanulók
névsora tanulmányi átlaguk szerint:');
End;
Procedure Osztatlag;
Var Jsz: integer;
Ossz: real;
S: String;
Begin
Szinek(1,0); ClrScr;
Jsz:=0; Ossz:= 0; S:= '';
For
I:= 1 To Amax Do
With
TTanulo[I] Do If Atl<>0 Then
Begin
Inc(Jsz);
Ossz:= Ossz+Atl;
End;
If
Jsz<>0 Then Atlag:= Ossz/Jsz;
Str(Atlag:4:2,S);
Uzenet(5,15,'Az osztály átlaga: '+S);
End;
Procedure Stati;
Var Amp:byte;
Const Amsor:
Array[1..6] Of String[17]=
(' Névsor szerint ',
' Korok szerint ',
' Lakhely szerint ',
' Átlag szerint ',
' Osztály átlaga ',
' Főmenű ');
Begin
If
Not Adatbent Then
Begin
Uzenet(5,15,'Nincs megnyitva
adatállomány!');
Exit;
End;
Repeat
Szinek(1,0);
ClrScr;
Ablak(7,0,29,8,49,15,True,'Lekérdezések:');
For
I:= 1 To 6 Do WriteXY(31,8+i,Amsor[i]);
Tunj;
Amp:= Menu(7,0,2,31,9,17,6,1);
Case
Amp Of
1: Nevszerint;
2: Korszerint;
3: Lakszerint;
4: Atlszerint;
5: Osztatlag;
6: Exit;
End;
Until
False;
End;
Begin
TextMode(CO80);
Init;
Repeat
Szinek(1,0);
ClrScr;
Ablak(7,0,30,8,48,13,True,'Főmenű:');
For
I:= 1 To 4 Do WriteXY(32,8+i,Msor[i]);
Tunj;
Mp:= Menu(7,0,2,32,9,15,4,1);
Case
Mp Of
1: Begin
Lemezrol; Nevtolto End;
2: Begin
Javitas; Nevtolto End;
3: Begin
Stati; Nevtolto End;
4: Begin
If Adatvalt Then
If
Kerdezo(5,15,'Lemezre menti-e a megváltozott adatokat?') Then Lemezre;
Szinek(0,7); ClrScr; Halt
End;
End;
Until
False;
End.
A
Tanulok nevű program kódolási
sorrendje:
Keretprogram;
Deklarációk;
Init;
Lemezre;
Lemezrol;
Nevtolto;
Javitas;
Stati;
Nevszerint;
Korszerint;
Lakszerint;
Atlszerint;
Osztatlag.
Gyakran gondot jelent, hogy a DOS-ban megirt
programjaink adatállományait nem tudjuk programból szép formátumban papírra
vetni. Ezen segít a következő kis eljárás, amely olyan szöveges állományt hoz
létre, amely könnyen betölthető az Excel táblázatkezelőbe. Ezután már könnyedén
formázhatjuk, szépíthetjük irományunkat. A most következő rutint a Tanulok listájába kell beszúrni,
valamint a főmenüt bővíteni kell egy 'TXT-file' menüponttal.
Procedure
TxtFile;
Var I: Integer;
TxtFNev: Text;
TxtDNev: String;
Begin
TxtDNev:= 'diakok.txt';
Assign(TxtFNev,TxtDNev); ReWrite(TxtFNev);
For
I:= 1 To Amax Do With TTanulo[I] Do
Write(TxtFNev,Nev,#9,Szul,#9,Oszt,#9,Lak,#9,Atl,#13);
Close(TxtFNev);
End;
Adatainkat az Excel-ből még tovább
vándoroltathatjuk, ha Word-ben formaleveleket szeretnénk írni. Megtehetjük,
hogy körlevél készítésnél a törzsadatoknak az Excel-ből kimentett állományunkat
választjuk, így a DOS-os felületen bevitt adataink végül egy Word dokumentumban
jelennek meg.
Egy String
input esetén a bevitt szöveg tartalmazhat fölösleges SPACE-eket, akár az elején
vagy a végén, de a string belsejében is. Írjunk a CrtPlus-ba egy olyan függvényt,
mely a fölösleges üres helyeket kitörli a szövegből. Legyen ennek a függvénynek
a neve: ValidSt.
Function ValidSt(s: String):
String;
Var I, N: Byte;
Ws: String;
Van: Boolean;
Begin
N:= Length(S);
ValidSt:= '';
If
N=0 Then Exit;
Ws:= S;
While
Ws[N]=' ' Do
Begin
Ws:= copy(Ws,1,N-1);
Dec(N);
End;
If
N>0 Then
While
Ws[1]=' ' Do
Begin
Ws:= Copy(s,2,N-1);
Dec(N);
End;
Van:= True;
If
N>3 then While Van Do
Begin
Van:= False;
N:= Length(Ws);
For I:= 2 To N-1 Do If (Ws[I]=' ') And (Ws[I+1]=' ') Then
Begin
Van:= True;
Ws:= Copy(Ws,1,I) + Copy(Ws,I+2,N-I-1);
End;
End;
ValidSt:= Ws;
End;
Gyakran lehet szükség arra, hogy string-listákat
kezeljünk, rendezéseket, kereséseket hajtsunk végre. A következő függvény
gyakorlatilag egy olyan lista, mely stringeket tud tárolni, a listában csak
egyszer szerepelhet egy string, és a tárolás rendezetten történik. Új lista
létrehozásakor először a Tomb[1..Max] string tömböt üres stringekkel kell
feltölteni. Mindannyiszor, amikor egy stringet ráhelyezünk a listára, a Listara függvényt kell meghívni a
ráhelyezendő stringgel, mint paraméterrel. Az átvett stringet a függvény
először a ValidSt függvény
segítségével megszabadítja a fölösleges SPACE-ektől. A lista függvény
visszaadott értéke a lista új hossza. A lista üres stringet nem tartalmazhat,
és a tárolás növekedő nagyságrendben történik. Ha a listát üres stringgel hívjuk
meg, akkor megkapjuk az aktuális hosszát. Ha a meghívással a lista hossza nem
változik, akkor a paraméterként átadott string már szerepel a listában. (pl: ha
Listara(’’)=Listara(’alma’) akkor az ’alma’ string már szerepel a listán.) A
leírtakból az is kitűnik, hogy ez a lista ezzel a függvénnyel csak növelhető,
szabályos törlésre nincs lehetőség. A Listara
függvény helye a CrtPlus unit-ban van. Mivel a függvény a listára helyezés előtt
egyszerű string összehasonlítást végez, a Listara
a kis- és nagybetűket megkülönbözteti.
Function
Listara(S: String): Integer;
Var I, J, N:
Integer;
Begin
S:= ValidSt(S);
N:=0; While
Tomb[N+1]<>'' Do Inc(N);
If
S='' Then Begin Listara:= n; Exit End;
If N=0
Then Begin Tomb[1]:= S; Listara:= 1; Exit end;
For
I:= 1 to N Do If Tomb[I]=S Then Begin Listara:= n; Exit End;
I:= 1;
While (S>Tomb[I]) And (Tomb[I]<>'')
Do Inc(I);
For
J:= N DownTo I Do Tomb[J+1]:= Tomb[J];
Tomb[I]:= S;
Listara:= N+1;
End;
Most írjunk egy olyan függvényt, amely a
listáról elemeket tud levenni. Legyen ennek a neve: Listarol és természetesen ez is a CrtPlus-ban lesz elhelyezve.
Function
Listarol(S: String): Integer;
Var I, J, N:
Integer;
Begin
S:= ValidSt(S);
N:= 0;
While Tomb[N+1]<>'' Do
Inc(N);
If
(S='') Or (N=0) Then Begin Listarol:= N;
Exit End;
For
I:= 1 To N Do If Tomb[I]=S Then
Begin
For
J:= I To N-1 Do Tomb[J]:= Tomb[J+1];
Tomb[N]:= '';
Listarol:= N-1;
Exit;
end;
Listarol:= 0;
End;
A Listarol
függvény tehát leveszi a listáról az átvett stringet, visszaadott értéke a
lista új hossza, ha pedig nem volt a listán, a visszaadott érték 0. Ha üres
stringgel hívjuk meg, akkor a visszaadott érték a lista aktuális hossza. Mivel
a levétel előtt validálást hajt végre, nem érzékeny a fölösleges SPACE-ekre.
34. Írjunk
programot, amely hozzáfűzésre megnyit egy szöveges állományt, majd üres string
beírásáig a billentyűzetről strigeket olvas, amelyeket a megnyitott lemezes
állomány végéhez hozzáfűz. Az input végeztével betölti a lemezről a stringeket,
és sorrendbe rakva visszaírja ugyanabba az állományba. Használjuk a Listara függvényünket.
Program
TextFile;
Uses NewDelay,
Crt, CrtPlus;
Var NevSor:
Text;
NevSorOS: String;
Procedure
AdatBe;
Var S: String;
Begin
S:= ' ';
Assign(NevSor, NevSorOS); {$I-}Append(NevSor);{$I-}
If
IOResult=0 Then ReWrite(NevSor);
While
S<>'' Do
Begin
ReadLn(S);
If
S<>'' Then WriteLn(NevSor, S);
End;
Close(NevSor);
End;
Procedure
Rendez;
Var S: String;
I, Sh: Integer;
Begin
ClrScr;
For
I:= 1 To Max Do Tomb[I]:= '';
Assign(Nevsor, NevSorOS); Reset(NevSor);
While
Not EOF(NevSor) Do
Begin
ReadLn(NevSor, S);
Listara(S);
End;
Close(NevSor);
I:= 1;
Sh:= 0;
Assign(NevSor, NevSorOS); Rewrite(NevSOr);
While
Tomb[I]<>'' Do
Begin
WriteLn(NevSor, Tomb[I]);
If
Length(Tomb[I])>Sh Then Sh:=
Length(Tomb[I]);
Inc(I);
End;
Close(Nevsor);
ClrScr;
Dec(I);
Listazo(7,0,2,20,2,Sh+6,I,5,1,True,'Lista');
End;
Begin
TextMode(CO80);
Szinek(1,14);
ClrScr;
NevSorOS:= 'NevSor.Txt';
AdatBe;
Rendez;
Varj;
End.
Az AdatBe
eljárás először hozzáfűzésre próbálja megnyitni az állományt, ha ez nem
sikerül, akkor ReWrite-tal. Majd billentyűzetről olvas üres string végjelig. A Rendez eljárás a file végéig (EOF)
olvassa a lemezes állományt, közben a stringeket listára teszi. Majd lezárja és
írásra megnyitja az állományt, és a teljes listát kiírja az állományba. Végül a
listát a listázóban megtekinthetjük.