Štrukturované údajové typy
29.11.2009 23:12Znakové reťazce
Znakový reťazec je údajový typ, ktorý obsahuje nejakú postupnosť znakov (Char). Znaky v znakovom reťazci (t.j. v postupnosti znakov) sú očíslované od 1 až po momentálnu dĺžku reťazca. Túto dĺžku zistíme pomocou štandardnej funkcie Length.
Delphi si uchováva dĺžku v 4 bajtoch, t.j. teoreticky by maximálna dĺžka mohla byť 4 gigabajty - v skutočnosti je obmedzená možnosťami Windows.
Premennú typu znakový reťazec deklarujeme takto:
var Retazec: string;
Premennej Retazec môžeme priradiť, napr. reťazcovú konštantu:
Retazec := 'reťazec';
Premenná Retazec teraz obsahuje postupnosť znakov dĺžky 7: prvý znak je 'r', druhý 'e', atď. T.j. hodnota funkcie Length(Retazec) je teraz 7. Reťazcové konštanty sú uzavreté rovnako ako znakové konštanty v apostrofoch.
Premenná typu string môže obsahovať aj prázdny reťazec:
Retazec := '';
Vtedy je jej dĺžka 0.
Môžeme pracovať aj s jednotlivými prvkami postupnosti, t.j. s jednotlivými znakmi v reťazci. Napr.
Retazec := 'abcdef';
Retazec[3] := '*';
Najprv sme do Retazec priradili 5-znakový reťazec a potom sme v ňom zamenili 3-tí znak (znak 'c') za hviezdičku '*'. Nesmieme sa pritom odvolávať na znaky mimo rozsahu <1, momentálna dĺžka>, napr.
Retazec[10] := '+'; // reťazec má zatiaľ dĺžku len 6
spôsobí chybovú správu.
Okrem priradení môžeme reťazce zapisovať do textového súboru a tiež ich môžeme zo súboru čítať. Napr.
Write(Subor, premenná_typu_string ); // výpis hodnoty premennej
Read(Subor, premenná_typu_string ); // prečítanie riadka zo vstupu do premennej
Znakové reťazce môžeme porovnávať pomocou relačných operácií (=, <>, <, >, <=, >=). Reťazce sú usporiadané pomocou tzv. lexikografického usporiadania. Napr. platí
'abc' > 'ABC'
'Adam' < 'Eva'
'jana' < 'jano'
'Jana' < 'jana'
Postupne sa pri tom porovnáva znak za znakom: kým sú v oboch reťazcoch rovnaké, pokračuje sa v porovnávaní. Keď sa narazí na rozdielne znaky, tak sa tieto dva porovnajú navzájom a podľa toho sa nastaví celkový výsledok porovnania. Porovnávanie dvoch znakov sa robí podľa pravidiel Char: t.j. menší je ten znak, ktorý má menší ASCII-kód.
Operácia '+' slúži na zreťazenie reťazcov (hovoríme, že + je polymorfný operátor, lebo jeho funkčnosť závisí od typu operandov: iný význam má pre čísla a iný pre reťazce). Napr.
Retazec := 'abc'+'def'; // Retazec='abcdef'
Retazec := '';
for I := 1 to 10 do // Retazec='**********'
Retazec := Retazec + '*';
Krátke znakové reťazce
V Turbo pascale aj v Delphi funguje typ string, pri ktorom do hranatých zátvoriek zapíšeme maximálnu možnú dĺžku reťazca. Napr.
var Retazec: string[20];
Označuje, že premenná Retazec môže mať maximálnu dĺžku 20 znakov. Priradenie dlhšieho reťazca spôsobí automatické odhodenie všetkých znakov za 20. znakom. Napr. môžeme zapísať
var
Retazec: string[10];
begin
Retazec := 'abcd'+'efgh'+'ijkl'+'mnop';
Do premennej Retazec sa ale dostalo len prvých 10 znakov, t.j. s='abcdefghij'.
Podprogramy s reťazcami
Delphi ponúkajú sadu preddefinovaných (štandardných) podprogramov, ktoré pracujú s reťazcami. Medzi základné patria
Length(reťazec)
- táto funkcia vráti momentálnu dĺžku reťazca
SetLength(reťazcová_premenná, nová_dĺžka)
- táto procedúra nastaví novú dĺžku reťazca
- pre krátke reťazce nesmie presiahnuť deklarované maximum
- ak je menšia ako momentálna dĺžka, znaky na konci sa strácajú
- ak je väčšia ako momentálna, tak pridané znaky (od konca) majú nedefinovanú hodnotu
Copy(reťazec, od, koľko)
- táto funkcia vráti nový reťazec, ktorý je podreťazcom pôvodného
- z pôvodného reťazca sa zoberú znaky počínajúc od hodnoty od a zoberie sa maximálne koľko znakov
- ak je od mimo rozsahu indexov reťazca, funkcia vráti prázdny reťazec, t.j. '', napr.
Retazec := Copy('abcde', 2, 3); // Retazec='bcd'
Retazec := Copy('abcde', 7, 3); // Retazec=''
Retazec := Copy('abcde', 3, 5); // Retazec='cde'
Ak potrebujeme podreťazec od nejakého indexu až do konca, nemusíme vypočítať presný počet, ale môžeme použiť konštantu MaxInt, napr.
Retazec := Copy('abcde', 3, MaxInt);
Pos(podreťazec, reťazec)
- táto funkcia vráti začiatočný index prvého výskytu podreťazca v danom reťazci alebo 0, ak sa v reťazci podreťazec nenachádza, napr.
I := Pos('d', 'abcde'); // I=4
I := Pos('C', 'abcde'); // I=0
I := Pos('ba', 'abababab'); // I=2
Podprogram ktorý zistí počet všetkých výskytov podreťazca Slovo v reťazci Veta:
procedure TForm1.Button2Click(Sender: TObject);
var
Veta, slovo: string;
I, J, Pocet: Integer;
begin
Veta := Edit1.Text;
Slovo := Edit2.Text;
Pocet := 0;
J := 0;
repeat
I := Pos(Slovo, Copy(Veta, J+1, MaxInt));
if I > 0 then
begin
Inc(Pocet);
J := J+I;
end;
until I = 0;
Label1.Caption :='počet výskytov = ' + IntToStr(Pocet);
end;
V podprograme je použitá iná konštrukcia cyklu a to cyklus repeat:
- tento cyklus opakovane vykonáva telo cyklu (príkazy medzi slovami repeat a until) a po každom takomto vykonaní týchto príkazov, otestuje podmienku cyklu (logický výraz za slovom until) - keď je podmienka splnená (hodnota je True), cyklus končí a pokračuje sa príkazmi za cyklom; keď je podmienka nepravdivá (hodnota je False), cyklus pokračuje - hovoríme tomu podmienka ukončenia cyklu
- tento cyklus sa teda správa "opačne" ako cyklus while
- telo cyklu sa vykoná vždy aspoň raz, aj keď je podmienka hneď na začiatku splnená
V ďalšom príklade opäť využijeme repeat-cyklus: všetky výskyty znaku ' ' nahradíme '***':
repeat
I := Pos(' ', Retazec);
if I > 0 then
Retazec := Copy(Retazec, 1, I-1) + '***' + Copy(Retazec, I+1, MaxInt);
until I=0;
Delete(Retazec, od, kolko)
- Retazec je znaková premenná
- od a kolko sú celočíslené hodnoty
Funkcia zmení reťazec Retazec, tak, že z neho vypustí kolko znakov od pozície od.
Vedeli by sme ju zapísať napr. takto:
procedure Delete(var Retazec: string; Od, Kolko: Integer);
begin
Retazec := Copy(Retazec, 1, Od-1) + Copy(Retazec, Od+Kolko, MaxInt);
end;
Insert(Retazec, Premenna, Od)
- Retazec je znakový reťazec (napr. premenná, konštanta alebo reťazcový výraz)
- Premenna je znaková premenná
- Od je celočíslená hodnota
Procedúra vloží podreťazec Retazec do reťazca Premenna od pozície Od
Vedeli by sme ju zapísať napr. takto:
procedure Insert(const Retazec: string; var Premenna: string; Od: Integer);
begin
Premenna := Copy(Premenna, 1, Od-1) + Retazec + Copy(Premenna, Od, MaxInt);
end;
Str(číslo, Retazec)
- číslo je celočíslená alebo reálna hodnota
- Retazec je reťazcová premenná
Procedúra prevedie číslo do znakového reťazca, napr.
Str(123, Retazec); // Retazec='123'
Str(-5.72, Retazec); // Retazec='-5.72'
Str(123:5, Retazec); // Retazec=' 123'
Str(-5.72:7:3, Retazec); // Retazec=' -5.720'
Zjednodušene by sme ju vedeli naprogramovať napr. takto:
procedure Str(Cislo: Integer; var Retazec: string);
var
Znamienko: Boolean;
begin
Znamienko := Cislo < 0;
if Znamienko then
Cislo := -Cislo;
Retazec := '';
repeat
Retazec := Char(Cislo mod 10+Ord('0')) + Retazec;
Cislo := Cislo div 10;
until Cislo = 0;
if Znamienko then
Retazec := '-' + Retazec;
end;
Táto procedúra sa používa už veľmi zriedka - v Delphi sa dá väčšinou nahradiť funkciami IntToStr alebo FloatToStr
Val(Retazec, Cislo, Index)
- Retazec je znakový reťazec
- Cislo je celočíslená alebo reálna premenná
- Index je celočíselná premenná - v nej nám vráti informáciu, či bol reťazec korektné číslo (0 je ok, inak pozícia v reťazci, kde nastala chyba)
Procedúra prevedie reťazec na číslo, napr.
Val('123', Cislo, Index); // Cislo=123, Index=0 - prevod bol v poriadku
Val('123, 124', Cislo, Index); // Cislo=?, Index=4 - pozícia chyby
Val('- 123', Cislo, Index); // Cislo=?, Index=2
Val('123 ', Cislo, Index); // Cislo=?, Index=4
Zjednodušene by sme ju vedeli zapísať napr. takto:
procedure Val(const Retazec: string; var Cislo, Index: Integer);
var
Znamienko: Boolean;
begin
Index := 1;
Cislo := 0;
Znamienko := Retazec[1]='-';
if Znamienko then
Index := 2;
while (Index <= Length(Retazec)) and (Retazec[Index] >= '0') and (Retazec[Index] <= '9') do
begin
Cislo := Cislo*10+Ord(Retazec[Index])-Ord('0');
Inc(Index);
end;
if Index > Length(Retazec) then
begin
Index := 0;
if Znamienko then
Cislo := -Cislo;
end;
end;
Táto procedúra sa používa len zriedka - v Delphi sa dá najčastejšie nahradiť funkciami StrToInt, StrToIntDef a StrToFloat.
Typ interval
Interval je taký typ, ktorý je odvodený z nejakého už existujúceho ale ordinálneho typu - hovoríme mu bázový typ. Typ definujeme tak, že určíme minimálnu a maximálnu konštantu tohto nového typu. Napr. ak zapíšeme
1 .. 10
znamená to, že vytvárame podtyp celých čísel (lebo sú to celočíselné konštanty) a tento nový typ obsahuje všetky konštanty z intervalu <1, 10>. Automaticky zo svojho bázového typu (Integer) preberá všetky vlastnosti a operácie. Napr. môžeme zadefinovať nový typ a potom aj premennú
type
TInterval = 1..10;
var
X: TInterval;
premenná X môže nadobúdať len hodnoty z tohto intervalu. Ak by sme sa pokúsili do nej priradiť nejakú inú hodnotu (napr. 0), Delphi by hlásil chybu. Inak pracujeme s touto premennou rovnako ako s obyčajnou celočíselnou premennou.
Pretože typ interval je tiež ordinálny typ, môžeme ho použiť, napr. aj vo for-cykle aj v príkaze case. Ešte je tu jeden rozdiel od typu Integer - typ interval môže v pamäti zaberať menej miesta ako jeho bázový typ, napr. v našom príklade premenná X zaberá iba jeden bajt (8 bitov). Typ interval môžeme odvodiť aj od iných ordinálnych typov, napr.
type
TMaleCislo = -100..100;
TRoky = 1900..2100;
TCeleCislo = Integer;
TBajt = 0..255;
TCifry = '0'..'9';
TPismena = 'A'..'Z';
Takejto definícii nového typu hovoríme priama definícia, lebo typ definujeme v odseku definície typov. Typ môžeme definovať aj nepriamo pri deklarovaní premennej, napr.
var
MalePis: 'a'..'z';
Typ pole
Definujeme:
type
TPole = array [typ_indexu] of typ_prvkov;
Pole sa skladá z veľa "jednoduchších" premenných, tzv. prvkov poľa. Všetky tieto prvky sú rovnakého typu. Pristupujeme k nim (selekcia) pomocou, tzv. indexu. Typom indexu môže byť ľubovoľný ordinálny typ. Typom prvkov poľa môže byť ľubovoľný typ. Štruktúra pole v pamäti zaberá toľko miesta, koľko zaberá jeden prvok krát počet prvkov poľa, t.j. počet rôznych hodnôt typu indexu. Napr.
type
TMojePole = array [1..100] of Integer;
definuje pole ktoré bude mať 100 prvkov (premenných) a keďže každý prvok zaberá 4 bajty, celé toto pole zaberá 400 bajtov. Delphi dovolí zadeklarovať maximálne 2 GB štruktúru, ale Windows má k dispozícii pre aplikáciu väčšinou len niekoľko desiatok až stovák MB. Napr.
type
Typ1 = array [Integer] of Byte; // zaberá presne 4 GB - to je už veľa
Typ2 = array [Byte] of Integer; // 1 KB (1024 B)
Typ3 = array [Char] of Boolean; // 0,25 KB (256 B)
Ak zadeklarujeme
var
P: TMojePole;
označuje to jednu premennú P typu TMojePole. Už vieme, že táto premenná zaberá 400 bajtov, lebo v sebe obsahuje 100 celočíselných premenných - prvkov. Ku každému prvku pristupujeme pomocou indexu, t.j. pomocou hodnoty z prípustného intervalu podľa deklarácie - v našom prípade indexom musí byť hodnota z intervalu 1..100. Ak chceme pracovať so samostatným prvkom, index zapisujeme do hranatých zátvoriek, napr.
P[5] := 37;
zmení obsah 5-teho prvku. S prvkami poľa pracujeme úplne rovnako ako s obyčajnými premennými.
Môžeme použiť pomocné funkcie pre pole (nech type TypX = array [-3..15] of Real;):
- funkcia High - vráti maximálny index poľa, napr. High(TypX) je 15
- funkcia Low - vráti minimálny index poľa, napr. Low(TypX) je -3
- funkcia Length - vráti počet prvkov (rovnako ako pre string vráti momentálnu dĺžku reťazca), napr. Length(TypX) je 19
Funkcie Low a High pracujú aj pre ľubovoľné ordinálne typy a premenné:
- funkcia High - vráti maximálnu prípustnú hodnotu typu, napr. High(Byte) je 255
- funkcia Low - vráti minimálnu prípustnú hodnotu typu, napr. Low(Char) je #0.
Polia ako parametre podprogramov
Formálne parametre typu pole môžu byť troch typov:
- var-parameter - nevyhradzuje sa žiadna nová pamäť, ale podprogram priamo manipuluje so skutočným parametrom, teda s celým poľom
- const-parameter - podobne ako var-parameter, len je zakázané v podprograme toto pole meniť, t.j. do neho niečo priraďovať
- hodnotový parameter - pri volaní podprogramu sa vytvorí duplikát celého poľa (rovnakej veľkosti) a vďaka tomu môžeme modifikovať tento duplikát (lokálnu premennú) bez toho, aby sa menil skutočný parameter. Treba dávať pozor na použitie tohto typu formálneho parametra, ak je to pole. Okrem toho, že spomaľuje výpočet, veľmi míňa pamäť pre lokálne premenné a často program na tomto aj hlási chyby.
Pri definovaní formálnych parametrov nesmieme nepriamo definovať nový typ, t.j. môžeme uvádzať len identifikátory už zadeklarovaných typov.
Aj výsledkom funkcie môže byť typ pole ale tiež musí byť vždy zadaný identifikátorom typu. Vysvetlime si, ako funguje volanie funkcie, ktorej výsledkom je typ pole:
- vyhradia sa všetky lokálne premenné (aj hodnotové formálne parametre)
- vyhradí sa jedna špeciálna lokálna premenná Result, ktorá je rovnakého typu ako typ funkcie, teda pole - táto premenná má zatiaľ nedefinovanú hodnotu
- s touto premennou pracujeme vo funkcii ako s iným bežným poľom
- po skončení výpočtu funkcie sa "zabudnú", t.j. uvoľnia všetky lokálne premenné, len hodnota Result sa stane výsledkom celej funkcie.
Chybné použitie typov:
procedure A(B: array [1..10] of Char);
procedure X(Y: 1..10);
function F(Z: Char): array [1..10] of Char;
Polia rôznych typov
Typ prvkov poľa môže byť ľubovoľný existujúci typ. Vo väčšine doterajších príkladov sme sa zameriavali na polia celých čísel. Stručne na príkladoch ukážeme využitie niektorých iných typov prvkov polí.
Pole číslic
Celé číslo môžeme rozložiť po cifrách do prvkov poľa. Takto môžeme reprezentovať aj oveľa väčšie čísla ako povoľuje Integer (hoci aj 1000-ciferné). Keď zvládneme naprogramovať niektoré aritmetické operácie nad takýmito veľkými číslami, môžeme veľmi presne uskutočniť niektoré výpočty, s ktorými sú inak problémy, napr. faktoriál, Fibonacciho čísla a pod. Nasledujúci program prečíta celé číslo, prevedie ho do poľa cifier, vynásobí ho dvoma a vypíše bez úvodných núl:
type
TVelkeCislo = array[1..1000] of 0..9;
var
Cislo: TVelkeCislo;
I, Prenos, N: Integer;
begin
Readln(N);
for I := 1 to High(Cislo) do
begin
Cislo[I] := N mod 10;
N := N div 10;
end; // násobenie dvomi
Prenos := 0;
for I := 1 to High(Cislo) do
begin
N := 2 * Cislo[I] + Prenos;
Cislo[I] := N mod 10;
Prenos := N div 10;
end; //výpis
I := High(Cislo);
while (I > 1) and (Cislo[I] = 0) do
Dec(I);
for I := I downto 1 do
Write(Cislo[I]);
Writeln;
...
end;
Pole znakových reťazcov
Údajová štruktúra pole môže mať prvky ľubovoľného typu, teda aj znakový reťazec. S takýmito premennými, ktoré sú prvkami poľa, sa pracuje rovnako ako s jednoduchými premennými typu reťazec. Nasledujúci program ilustruje použitie poľa znakových reťazcov:
var
Subor: TextFile;
Pole: array [1..1000] of string;
I, J, N: Integer;
begin
AssignFile(Subor, 'unit1.pas');
Reset(Subor);
N := 0;
while not Eof(Subor) and (N < High(Pole)) do
begin
Inc(N);
Readln(Subor, Pole[N]);
end;
CloseFile(Subor);
for I := 1 to N do
for J := 1 to Length(Pole[I]) do
if (J = 1) or (Pole[I][J-1] = ' ') then
Pole[I][J] := UpCase(Pole[I][J]);
Memo1.Clear;
for I := 1 to N do
Memo1.Lines.Append(Pole[I]);
end;
Tento program najprv prečíta riadky textového súboru a skôr ako ich vypíše do textovej plochy Memo1, každému slovu zmení prvé písmeno na veľké.
Zápis Pole[I][J] označuje J-ty znak I-teho reťazca - môžeme to zapísať skrátene: Pole[I, J].
Vymenovaný typ (enumerated type)
Vymenovaný typ je taký ordinálny typ, ktorý definujeme vymenovaním všetkých prípustných hodnôt daného typu. Vymenované hodnoty sú identifikátory konštánt (ich ordinálne hodnoty sú čísla od 0 do počet-1), napr.
type
TTyzden = (PON, UTO, STR, STV, PIA, SOB, NED);
definuje nový ordinálny typ - premenné tohto typu budú môcť nadobúdať hodnotu len z tohto zoznamu konštánt. Vymenovaný typ nie je kompatibilný so žiadnym iným typom (napr. interval preberá všetky vlastnosti aj konštanty nadradeného typu a tiež je s ním kompatibilný - dovoľuje navzájom sa priraďovať, miešať sa v operáciách a pod.)
Deklarácia vymenovaného typu okrem samotného typu automaticky definuje aj identifikátory konštánt tohto typu, t.j. s deklaráciou typu TTyzden sa zadeklarovalo aj 7 nových identifikátorov konštánt. Nakoľko je vymenovaný typ ordinálny typ, fungujú s ním všetky štandardné funkcie a procedúry, ktoré pracujú s inými ordinálnimi typmi (Integer, Char, Boolean):
- štandardné funkcie, procedúry: Ord, Pred, Succ, Low, High, Inc, Dec
- môžeme ho použiť ako index prvkov poľa, resp. riadiaca premenná for-cyklu
- fungujú všetky relácie: =, <>, <=, >=, <, >
- aj na typ Boolean by sme sa mohli pozerať ako na vymenovaný typ, t.j. ako keby
type Boolean = (False, True);
- vymenovaný typ sa nedá vypísať ani prečítať do, resp. zo súboru
- ordinálna hodnota je definovaná tak, že prvá konštanta typu má vnútornú hodnotu 0 a všetky ďalšie postupne o 1 viac, t.j.
Ord(PON) = 0; Ord(UTO) = 1; Ord(STR) = 2; ... Ord(NED) = 6;
- meno typu (v našom prípade TTyzden) je automaticky menom konverznej funkcie, ktorá z celého čísla vyrobí príslušnú konštantu vymenovaného typu, napr.
TTyzden(2) = STR; TTyzden(5) = SOB;
Príklad s vymenovaným typom:
type
TTyzden = (PON, UTO, STR, STV, PIA, SOB, NED);
var
D: TTyzden;
begin
D := PON;
D := Pred(PIA); // D=STV
D := Succ(SOB); // D=NED
D := UTO;
Inc(D); // d=str
Inc(D, 3); // d=sob
I := Ord(PON); // I=0 prvá konštanta má hodnotu 0
I := Ord(UTO); // I=1
D := TTyzden(4); // D=PIA
D := Low(TTyzden); // D=PON
D := High(D); // D=NED
end;
Všimnime si, že sme identifikátor nového typu TTyzden použili ako meno funkcie, ktorá konvertuje celé číslo na vymenovaný typ.
Ak potrebujeme hodnoty vymenovaného typu prečítať alebo vypísať, tak buď pri vstupe/výstupe pracujeme iba s ordinálnymi hodnotami, alebo si vytvoríme pomocné pole mien konštánt, napr.
const
Nazvy: array [TTyzden] of string = ('pon', 'uto', 'str', 'stv', 'pia', 'sob', 'ned');
var
Ret: string;
begin
Ret := Edit1.Text;
D := Low(TTyzden);
while (D < High(TTyzden)) and (Nazvy[D] <> Ret) do Inc(D);
if Nazvy[D] <> Ret then
Memo1.Lines.Append('... chyba ...')
else
Memo1.Lines.Append(Nazvy[[[Succ]](D)]); // spadne, ak d=ned
end;
Vymenovaný typ sme už používali predtým, napr. nasledujúce typy sú už preddefinované v knižniciach Delphi:
type
TPenStyle = (psSolid, psDash, psDot, psDashDot, psDashDotDot, psClear, psInsideFrame);
TBrushStyle = (bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross);
// a preto sme mohli písať:
Image1.Canvas.Pen.Style := psDash;
Image1.Canvas.Brush.Style := bsClear;
V nasledujúcom príklade funkcia Porovnaj vráti jednu z hodnôt vymenovaného typu (Mensi, Rovny, Vacsi) podľa toho, v akej relácii sú dva reťazce:
type
TPorovnanie = (Mensi, Rovny, Vacsi);
function Porovnaj(Ret1, Ret2: string): TPorovnanie;
begin
if Ret1 < Ret2 then Result := Mensi
else if Ret1 = Ret2 then Result := Rovny
else Result := Vacsi;
end;
Iné možnosti definovania konštánt vymenovaného typu
Zatiaľ sme sa naučili, že prvá konštanta vymenovaného typu má ordinálnu hodnotu 0 a posledná počet-1. Toto pravidlo môžeme podľa potreby zmeniť: pri definovaní vymenovaného typu môžeme zároveň definovať aj ordinálne hodnoty konštánt, napr.
type
TPorovnanie = (Mensi=-1, Rovny, Vacsi=3);
Pritom platí:
- ak je za konštantou (za znakom rovná sa) celé číslo, toto definuje jeho ordinálnu hodnotu
- ak prvá konštanta nemá definovanú žiadnu hodnotu (napr. pon v Tyzden), tak dostáva hodnotu 0
- ak niektorá konštanta (okrem prvej) nemá definovanú svoju ordinálnu hodnotu, automaticky dostáva o 1 vyššiu ako predchádzajúca konštanta
- viac identifikátorov konštánt môže mať rovnaké ordinálne hodnoty
- medzi minimálnou a maximálnou hodnotou nemusia byť všetky ordinálne hodnoty pomenované konštantami, napr. v type Porovnanie má konštanta rovny hodnotu 0 a hodnotu 2 sme nepomenovali - aj tak môže premenná takéhoto vymenovaného typu nadobúdať aj nepomenované hodnoty, napr.
var
P: TPorovnanie;
begin
P := TPorovnanie(2);
Z tohto vyplýva, že pre vymenovaný typ je dôležitá minimálna a maximálna konštanta - tieto dve definujú interval a všetky ostatné konštanty len pomenúvajú niektoré hodnoty z daného intervalu, napr.
type
TCislo = (Minc=1, Maxc=100, Spec=10);
definuje vymenovaný typ, ktorý je intervalom s ordinálnymi hodnotami 1..100, okrem toho je ešte definovaná jedna konštanta tohto typu spec s ordinálnou hodnotou 10. Aj pomocou const môžeme dodatočne zadefinovať ďalšie konštanty do vymenovaného typu, napr.
const
Extra = TCislo(27);
k trom konštantám typu Cislo dodefinoval ďalšiu s ordinálnou hodnotou 27.
Delphi poskytujú aj ďalšie knižničné funkcie na prácu s vymenovaným typom: GetEnumName a GetEnumValue umožňujú z ordinálnej hodnoty zistiť reťazec, resp. naopak, z reťazca získať ordinálnu hodnotu - popis týchto funkcií nájdete v Helpe
Typ množina
je taký údajový typ, ktorý v pascale umožňuje pracovať s niektorými typmi množín podobným spôsobom ako je to obvyklé v matematike. V pascale je povolené vytvárať množiny zložené len z prvkov rovnakého a to niektorého ordinálneho typu - hovoríme mu bázový (základný) typ. Napr. môžeme vytvoriť množinu znakov, množinu malých celých čísel, množinu dní v týždni a pod. Nemôžeme ale vytvoriť množinu, ktorá bude obsahovať napr. čísla aj znaky. Definícia množiny sa vždy skladá aj z definície jej bázového typu, napr. zápis
type
TMnozina = set of 1..100;
var
A, B: TMnozina;
definuje nový typ množina, ktorá môže obsahovať len čísla z intervalu (to je ordinálny typ) 1 až 100 - zrejme premenné takéhoto typu môžu byť napr. prázdna množina, alebo jednoprvková množina s prvkom 13 alebo dvojprvková množina s prvkami 2 a 3 a pod. Do premenných A, B môžeme priraďovať (iba množiny), môžeme s nimi manipulovať pomocou množinových operácií a relácií - nemôžeme ich priamo vypísať alebo prečítať do/zo súboru, musíme si to naprogramovať.
Ako pracujeme s typom množina:
- môžeme používať množinové konštanty:
- prázdna množina [],
- vymenovanie prvkov a intervalov [2], [1, 3], [1, 2, 3], [5..15, 20, 23..27]
- ale aj [1, 1, 1], [3, 3, 1], [1..2, 2..3, 1..3]
- množinové operácie musia mať oba operandy navzájom kompatibilné množiny (t.j. majú kompatibilné bázové typy):
- zjednotenie A := A + B;
- pridaj prvok: A := A + [5];
- prienik A := A * [2, 3];
- vyhoď prvok: A := A - [5];
- rozdiel A := B - [1, 3];
- príslušnosť prvku (prvý operand je bázového typu, druhý je množina):
- číslo 3 je prvkom množiny A: if 3 in A then ...
- hodnota premennej I nie je prvkom množiny B: if not (I in B) then ...
- relácie:
- rovnosť, nerovnosť: if A = B then if C <> [] then ...
- if A * [5] <> [] then ...
- podmnožiny: if (A <= B) or (A >= B) then ..
Realizácia množiny v pamäti počítača
Pascalovské množiny sú v pamäti počítača reprezentované ako postupnosť bitov, t.j. postupnosť 0 a 1. Napr. pre set of 0..99 je vyhradených 100 bitov, t.j. 13 bajtov. V I-tom bite je buď 0, ak I nepatrí do množiny alebo 1, ak I patrí do množiny. Priradenie a := []; vynuluje všetky bity. Priradenie a := [5, 7, 8]; nastaví na 1 iba bity 5, 7, 8, ostatné vynuluje. Množinová operácia a + b postupne ide po bitoch v oboch postupnostiach a aj b a robí operáciu binárne OR, t.j. ak aspoň v jednej z nich je 1, tak aj vo výsledku bude 1. Pre množiny set of baza musí platiť: 0 <= Low(baza) <= High(baza) <= 255. To znamená, že takto nevyrobíme množiny s viac ako 256 prvkami. Najväčšia možná množina set of Byte zaberá 32 bajtov.
Väčšie množiny môžeme reprezentovať pomocou poľa množín - budeme tomu hovoriť "veľké množiny". Napr. ak by sme potrebovali množinu s 1000 prvkami, t.j. postupnosť 1000 bitov, položíme tesne za seba 4 množiny po 256 prvkoch a budeme predpokladať, že
- v prvej množine budú prvky od 0 do 255
- v druhej množine budú prvky od 256 do 511 - budú ale posunuté tak, že 256 bude mať v druhej množine číslo 0, t.j. o 256 menej
- v tretej množine budú prvky od 512 do 767 - prvky budú posunuté o 512
———
Späť