MFF UK / Ústav teoretické fyziky / Tomáš Ledvinka
Přednášky
. . . . . . . . . . . . . . . . . . . . . . . . . .
Programování pro fyziky (1.r)
  Úvod
  Programy a algoritmy
  Píšeme program
  Píšeme program II
  Procedury a funkce
  Malujeme funkce
  Chyby. Typy I.
  Typy II. Pole a Záznamy
  Pole II.Řetězce.Soubory.
    With a Case
    Pole, zarážky etc.
    Dynamická pole
    Řetězce
    Text a spol
  Gnuplot.Interpolace...
  Matice. Velké O...
  Fronta,Zásobník. Postscript
  Bin. soubory, ...
  Ukazatele,Objekty, ...
Počítačová algebra
Klasická elektrodynamika (2.r)
Vybrané partie OTR

Cvičení
. . . . . . . . . . . . . . . . . . . . . . . . . .
Programování pro fyziky (1.r)
Teoretická mechanika (2.r)
Klasická elektrodynamika (2.r)


Věda
. . . . . . . . . . . . . . . . . . . . . . . . . .
Diskové zdroje v OTR
Hyperbolické systémy v OTR


Kontakt
. . . . . . . . . . . . . . . . . . . . . . . . . .
Email
Konzultační hodiny


Ostatní
. . . . . . . . . . . . . . . . . . . . . . . . .
Mallorca
Ze společnosti

Pole s volným koncem - zarážka

V mnoha případech neznáme v okamžiku kdy píšeme program, kolik hodnot bude v poli potřeba uskladnit. Běžným řešením je odhadnout shora maximální rozumný počet a pole dimenzovat na tuto maximální zátěž. Jde o velmi běžný postup a i některé solidní programy (TeX) vám někdy nahlásí, že jste vyčerpal kapacitu a musíte si program překompilovat s větší konstantou určující kapacitu polí pro uskladnění.

Jak ale do takovéhoto pole naskládat seznam s proměnnou délkou. Prvním řešením je použití zarážky. Jde o to, že za posledním uloženým prvkem nastavíme ten další na nějakou dohodnutou hodnotu, jež nás upozorní, že již nejde o data ale o oznámení konce. V kódu pak procházíme pole dokud nenarazíme na zarážku. Pokud je procházení pole součástí zamýšleného kódu, nepřidá kontrola na zarážku příliš práce a není ani příliš náročnější než si pamatovat rovnou počet údajů v poli. Technologie zarážky se běžně používá u jednoho typů polí: řetězců. Zatímco Pascal s implementací řetězců nejdříve otálel, jiný jazyk jeho éry, C, který musel od počátku sloužil pro psaní skutečných programů, rozhodl, že dnes je nejčastějším způsobem uložení řetězců takzvaný zero-terminated string. Nejčastějším proto, že dnešní OS mají kdesi na počátku právě operční systém, kvůli jehož psaní si K&R vymysleli jazyk C. Proto až budeme potřebovat komunikovat na nižší úrovni s OS, budeme se muset spokojit s touto nejjednodušší formou řetězce. V následujícím příkladu požádáme OS ( = Windows, konkrétně) aby nám sputili (angl. execute) program ping. Ten bez paramtrů vypíše nápovědu a skončí. Proceduře zajišťující komunikaci s OS, WinExec, musíme předat parametr právě jako nulovou zarážkou ukončené pole znaků. Proceduru WinExec nalezneme exportovanou v knihovně (UNIT) Windows, která exportuje 4373 funkcí, 92 procedur a 180typů, které můžete použít ke komunikai s aplikační vrstvou OS a jeho nadstaveb (tím se má říci, že když blufujeme o počítačích, hodí se rozlišovat v pro nás monolitním "OS" vlastní OS, nadstavby, vnitřnosti,...).

program pokus;

uses Windows;

var cmd : array[0..1234] of Char;
      i : integer;

begin
   cmd := 'ping'; // Nějaký "příkaz" reprezentovaný exe-souborem, nikoli copy či dir
   WinExec(cmd,1);// Řekni OS aby příkaz vykonal
   Sleep(1000);   // Za 1000 ms by to už mohlo být hotovo, WinExec totiž nečeká

   i := 0;        // Příklad velmi jednoduché práce znak po znaku
   while cmd[i]>#0 do begin
     writeln(cmd[i]);
     i:=i+1;
   end;

   readln;
end.

V cyklu while je vidět jednoduchý příklad na operaci s každým znakem nulou ukončeného řetězce. Příkaz
cmd:='ping'
ukazuje další z výjimek v kompatibilitě typů. Stručně je shrneme na konci přednášky. Zde jen, že by se to nepřeložilo, kdyby byl typ pole např. array[1..1234] of Char, tedy tyto nejen nulovým znakem ukončené (vlastnost uložení dat) ale i nulovým indexem počínající jsou (důležitá formalita).
Pozor, zarážka je jen jedna. Když ji přehlédnete, mohou za ní následovat bežné znaky a na další zarážku už v poli vůbec nemusíte narazit, index tak překročí hranice pole a mohou se začít dít věci.

Cvičení: Napište vnitřnosti následujících procedur:

type tStrZ = array[0..1024] of Char;

procedure SpojRetezce(const A,B: tStrZ; var AaZaNimB: tStrZ);

function DelkaRetezce(const A: tStrZ) : integer;

procedure KusRetezce(const A: tStrZ; OdKterehoZnaku,KolikZnaku: integer; var VybranuKusA: tStrZ);

Pole s volným koncem - proměnná pro délku

Je zřejmé, že místo abychom na určení délky řetězce měli zvláštní funkci, která jen počítá počet znaků před zarážkou, můžeme přidat ještě proměnnou, která bude vždy říkat, kolik hodnot máme v poli uloženo.
Typické použití je v následujícím kódu: Když už umíme ukládat řadu hodnot do pole, můžeme si ukázat jak tato data načteme z klávesnice.

{$RANGECHECKS ON} 
const Max = 1000;
var PocetHodnot : integer = 0; //inicializovaná proměnná
    Hodnoty     : array[1..Max] of real;
    x : real;
begin
 Writeln('Zadejte až ',Max,'kladných reálných čísel');
 Writeln('Zadávání ukončete záporným číslem nebo nulou.');
 
 ReadLn(x);  
 while x>0 do begin
   PocetHodnot :=  PocetHodnot + 1;
   Hodnoty[PocetHodnot] := x;
   ReadLn(x);  
 end;
 
 Writeln('Načetl jsem ', PocetHodnot, ' čísel. Příště s nimi i něco udělám');

end.

Takto obvykle vypadají programy z učebnic zpracovávající vstup dat . Jde o to načíst řadu čísel, něco s ní udělat (v našem případě jsme je jen naskládali do pole), přičemž konec vstupu je indikován nějakým číslem mimo rozsah povolených hodnot. Jakkoli jsme tedy odstranili zarážku z našeho popisu dat uvnitř programu, zůstala tu stále zarážka jako konečník vstupních dat.

Poprvé je zde použita funkce ReadLn k něčemu lepšímu než jen k čekání na stisk klávesy Enter. Jde o vylepšenou versi proceury Read, která umí načíst ze vstupu (nebo souboru, to uvidíme později) data několika základních typů: Celé číslo, reálné číslo, jeden znak a řetězec znaků (uvidíme dále). ReadLn pak ještě přečte a zahodí všechny znaky do konce řádku včetně. Naproti tomu Read pokračuje tam, co skončila.

Pole s volným koncem - proměnná pro délku a pole sbalené do záznamu

Proměnné Hodnoty a PocetHodnot jsou úzce svázány a zvláště ta první bez druhé není použitelná. Mohlo by nás napadnout spojit je do jednoho záznamu a chápat je jako jednu (strukturovanou) proměnnou.

type tHodnoty  = record 
          Pocet : integer;
          Data  : array[1..Max] of real;
     end;
   

Víme, že Pascal s nově definovaným typem příliš zacházet neumí, nezbude nám, než si pro něj napsat sadu procedur a funkcí a nebo jednoduše psát Hodnoty.Data[Hodnoty.Pocet]. V situaci, kdy náš program musí zacházet s několika různě dlouhými seznamy dat může spojení k sobě příslušných dat a metadat do jedné struktury zvýšit pohodlí a bezpečí.

.