#8 Rekurze a vlastní datové typy

Tato lekce se bude zabývat rekurzivnímu volání funkcí, dále také rozsahu platnosti proměnných. Hlavním bodem tohoto článku budou vlastní datové typy.

Rekurze

Rekurze je proces kde určitý objekt, v případě jazyka C je to funkce, se využívá sebou samým. Funkce obsahuje ve svém těle volání sebe sama a při každém volání jsou upravené předávané hodnoty. Rozlišujeme dva druhy rekurze:

  1. Přímá – uvnitř kódu funkce je volání té samé funkce
  2. Nepřímá – v kódu funkce se nachází volání druhé funkce, která opět zavolá funkci první

Na příkladu si znázorníme použití rekurze a syntaxi kódu, opět použijeme nám již známy výpočet faktoriálu:

#include <stdio.h>

int factorial(int n) {
    if (n > 1) 
        return n * factorial(n - 1);
    else 
        return 1;
}

int main(void)
{
    int number = 0;

    printf("Insert number: ");
    scanf("%d", &number);

    printf("Result: %i\n", factorial(number));

    return 0;
}

Rekurze je určitý druh cyklu, tudíž musí mít ukončovací podmínku, jinak by výpočet rekurze procházel čím dál více do hloubky a mohlo by dojít i k nekonečné hloubce.

Detailnější chování výpočtu rekurze, nám prozradí debugger. Ten obsahuje zajímavou pomůcku, kde si můžeme nastavit podmínku zastavení v rekurzi, jedná se o podmíněný breakpoint.

Vlasnosti breakpointu si zobrazite pravým kliknutím myši na breakpoint a klikněte na Edit breakpoint. Do položky Condition zapíšete podmínku podle které se debugger zastaví na určitém místě.

Rekurzivnímu řešení se raději vyhněte, pokud to samozřejmě není podmínkou příkladu. Jakákoliv rekurze lze zapsat cyklem, nejčastěji while, proto raději preferujte tuto volbu. Rekurze je náročnější vzhledem k výkonu počítače. Při zavolání nové funkce se spouštějí i nové instrukce procesoru a to předání parametru, předání návratové hodnoty a také alokace a dealokace paměti na zásobníku.

Rozsah platnosti proměnné

Deklarace lokální či globální proměnné se nijak neliší. Rozdíl mezi nimi je v rozsahu platnosti v programu.

Lokální proměnná

Pro lokální proměnnou jsou 3 možnosti jak jej deklarovat, myslí se kde, v jaké částí kódu se nachází:

  1. Funkce
  2. Blok
  3. Cyklus

Pří deklaraci proměnné ve funkci, se považuje za platnou až do ukončení funkce. Jedná se pouze o proměnné, které se nacházejí v hlavičce. Pokud bychom deklarovali proměnnou pod hlavičkou, tedy někde uprostřed kódu funkce. Jednalo by se o deklaraci v bloku. Blokem považujeme část kódu, která je ohraničená složenými závorkami. Jako u funkcí i u bloku je to stejné s rozsahem platnosti proměnné, tedy proměnná deklarovaná uvnitř bloku (např.: v podmínce if) zaniká při skončení bloku. Co se týče cyklů, tak proměnná deklarovaná v „hlavičce“ cyklu (platí pouze pro cyklus for) je platná pouze při provádění daného cyklu, po skončení zaniká.

Globální proměnná

Deklarace takovéto proměnné se nachází vně jakékoliv funkce. Platnost proměnné zaniká až při ukončení celého programu.

#include <stdio.h>

int number = 50;

void myFunc()
{
    number += 100;
}

int main(void)
{
    myFunc();
    printf("%d\n", number);
    return 0;
}

Za jakousi globální proměnnou lze považovat i identifikátor vzniklý pomocí direktivy #define. Ačkoliv pojmenování proměnná není správné, jelikož je konstantní a nedá se přepisovat. Rozsah platnosti může být stejný jako u globální proměnné, za předpokladu že se v kódu neprovede direktiva #undef, která by tento identifikátor odstranila.

Překrytí identifikátorů (proměnných)

Existuje možnost překrytí či zastínění proměnné. Například globální identifikátor může být překrytý lokálním identifikátorem (např.: v cyklu), který má sejný název. Používání překrývaní proměnných je nevhodné a zhoršuje se přehlednost kódu.

Vlastní datové typy

Prozatím jsme používali pouze vestavěné datové typy, jako např.: int, double, char. Nyní si však ukážeme jak vytvářet vlastní typy, pomocí kterých lze v jazyce C vytvářet rozsáhlejší konstrukce. Definice všech vlastních typů se zapisují mimo jakoukoliv funkci. Dle konvence se zapisuje ještě před definicí první funkce programu. Existují 4 druhy klíčových slov, bez kterých se vytvoření vlastního datového typu neobejde, jsou to:

  • enum
  • struct
  • union
  • typedef

1. Enum

Nejprve se zaměříme na enum. Pomocí něj lze vyvářet výčtový typ. Jednoduše lze říct, že enum slouží k pojmenování konstant. Obecná deklarace typu enum vypadá takto (zároveň vidíme i deklaraci proměnné, která používá nově definovaný typ):

enum nazev_typu {hodnota1,hodnota2,…}
enum nazev_typu nazev_promenne;

Při deklaraci typu jsou jednotlivé hodnoty ve složených závorkách oddělené čárkou. Při deklaraci proměnné nesmíme zapomínat napsat i zde klíčové slovo enum.

#include <stdio.h>
enum cisla {nula, jedna, dva};

int main(void)
{
    enum cisla cislo;
    cislo = dva;
    //cislo = tri; //error tri neni soucasti vyctoveho typu

    printf("%d\n", cislo);
    return 0;
}

Po spuštění ukázkového programu, ihned zjistíme, že konstrukce enum je vytvořená pomocí celočíselného typu, konkrétněji je to typ int. Dle výchozího nastavení se první položka inicializuje na hodnotu 0, další položka má hodnotu 1, atd.

Tyto hodnoty je možné změnit a to tak, že např.: jedné z položek ve výčtu přiřadíme konkrétní hodnotu.

enum muj_enum {automobil, letadlo = 5, kolo};
// auto = 4, letadlo = 5, kolo = 6

Hodnoty mohou být i stejné.

enum muj_enum {automobil = 7, letadlo = 7, kolo};
// auto = 7, letadlo = 7, kolo = 8

2. Struct

Jak již z pojmenování vyplývá, budou se pomocí slova struct vytvářet datové struktury. Jedná se o množinu proměnných různého datového typu, které jsou navzájem spojené. Každá proměnná má sice své pojmenování, ale celkové spojení musí mít také svůj název.

Obecná deklarace struktury:

struct nazev_typu {
	datovy_typ1 promenna1;
	datovy_typ2 promenna2;
	…
};

Vytvoření proměnné ve funkci:

struct nazev_typu promenna;

Podle obecné definice se nám může zdát, že je to v podstatě to samé co enum, ale není to úplné pravda, struct může mít libovolný datový typ ke každé své proměnné, třeba i další struct.

Ukázkový příklad nám napoví, k čemu vlastně slouží struct.

#include <stdio.h>

struct person_t {
    char name[255];
    unsigned short age;
};

int main(void)
{
    struct person_t person1 = {"Jan", 25};
    printf("%s, %d\n",person1.name,person1.age);

    struct person_t person2 = {.age = 20};
    printf("%s, %d\n",person2.name,person2.age);
    return 0;
}

Struct můžeme použít například k evidenci osob, protože samotná osoba má více položek, které je potřeba uchovat.

V příkladu jsou použity 2 různé deklarace proměnné, které používají stejný datový typ. První přiřazení je klasické, ale u druhého je použitá tečková notace, stejné jako při výpisu jednotlivých proměnných.

Právě pomocí operátoru tečka, přistupujeme k jednotlivým položkám ve structu.

Struct je tedy vhodný na již zmíněnou evidenci osob, ale abychom nemuseli deklarovat každou osobu zvláště, je jednoduší vytvořit pole. Deklaraci pole sice známe, ale pouze pro upřesnění je zde syntaxe:

struct person_t persons[1000];
persons[485].age = 25;

Také jako obyčejnou proměnnou i celé struktury lze kopírovat.

struct person_t person1 = {"Jan", 25};
struct person_t person2;
person2 = person1;

Musíme si však dát pozor, pokud struktura obsahuje datový typ ukazatel. Kopírování totiž způsobí, že 2 proměnné budou ukazovat na stejné místo v paměti a mohlo by docházet k nesprávným výsledkům.

3. Union

Typ union je stejný jako struct, jeho deklarace je totožná, s tím rozdílem, že se zamění klíčové slovo. Union se moc nepoužívá a je vhodnější použít struct. Odlišnost mezi structem a unionem je v tom, že struct zabírá v paměti tolik místa kolik je potřeba pro uchování všech jeho položek, kdežto union zabírá pouze tolik paměti jako jeho největší položka, je tedy jasné, že je možné použít pouze jednu položku v jeden moment. Je tedy možné říct, že všechny položky unionu sdílí jedno místo v paměti.

4. Typedef

Tento nástroj neslouží k vytvoření nějaké struktury různých datových typů jako předešlé 3 případy. Typedef slouží k pojmenovávání různých datových typů, šetří se tím zejména velikost kódu a stává se tím i přehlednější.

Obecný tvar:

typedef datovy_typ nazev_typu;

Pomocí typedef je možné si zkrátit zápis některých deklarací např.:

typedef unsigned short ushort;
typedef int matrix[3][3];

Lze také využít u deklarace structu, poté při deklaraci proměnné typu struct nebude již nutné vepisovat klíčové slovo, ale zapíše se pouze jeho zkrácený zápis vytvořený pomocí typedef:

typedef struct person_t {
    char name[255];
    unsigned short age;
} person;

person person1 = {"Jan", 25};

To bude vše k dnešní lekci, snad jste se zase něco nového dozvěděli a naučili.

#7 Rozdělení zdrojového kódu

V sedmé lekci kurzu programování v jazyce C si ukážeme, jak a k čemu je dobré rozdělovat zdrojový kód do více části, než právě do jedné velké funkce.

Již v druhé lekci jsme si popsali základní prvky, které funkce může nebo musí obsahovat. Klasická funkce by měla obsahovat návratový typ a také vstupní argumenty, na základě kterých se ve funkci vyhodnotí kód a funkce nám vrací nějaký výstup.

Rozdělení kódu do více funkcí je užitečné zejména proto, že celý kód se stává o mnoho přehlednější a je také snadnější na editaci. Je vhodné pro odstraňování duplicity kódu. Pokud potřebujete použít vícekrát stejný výpočet akorát s jinými parametry, jednoduše tuto část vyjměte jako novou funkci a poté ji spusťte kolikrát bude potřeba.

Deklarace funkce

Jsou dvě možnosti jak funkci deklarovat:

  1. samotná deklarace funkce a její definice se nachází později v kódu
  2. deklarace společně s definicí

Jak tomuto rozumět? Znázorníme si vše na příkladu.

void func1(int, char, double); //deklarace, nemusi obsahovat nazvy parametru
void func2(int number) //deklarace s definici
{
    //prikazy
}

int main(void)
{
    func1(0,'f',5.0);
    func2(0);

    return 0;
}

void func1(int number, char c, double pi) //definice funkce
{
    //prikazy
}

Pokud máte program, který má pouze jednu vlastní funkci, tak použijte deklaraci společně s definicí. Pro více funkcí a komplexnější programy je pro přehlednost vhodnější použít strukturu:

  • deklarace vlastních funkcí
  • funkce main
  • definice vlastních funkcí

Argumenty a proměnné ve funkci

Proměnné deklarované ve funkci jsou lokální, tzn. že po skončení funkce zanikají. Argumenty jsou také lokální proměnné. Při zavolání funkce se tyto proměnné vytvoří a zkopíruje se do nich hodnota, která jim při zavolání byla předána. Existují 2 možnosti předání argumentů:

  1. Předání hodnotou
  2. Předání hodnotou ukazatele

Rozdíly mezi těmito způsoby si ukážeme na příkladu, použijeme oddělené proměnné pro každý způsob.

void Afunc(int a) {a = 50;} //nastavime a na 50
void Bfunc(int* b) {*b = 80;} //nastavime b na 80

int main(void)
{
    int a = 10;
    int b = 20;

    Afunc(a); //predani hodnotou
    Bfunc(&b); //predani hodnotou ukazatele

    printf("%d\n", a); //a je opet 10
    printf("%d\n", b); //b se zmenilo na 80

    return 0;
}

Ještě si ukážeme jak předat funkci celé pole proměnných, aby jej bylo možno upravovat ve funkci.

#define MAX_ARRAY 10

void write(int* array)
{
    for (int i = 0; i < MAX_ARRAY; i++)
        array[i] = i;
}

void print(const int* array)
{
    for (int i = 0; i < MAX_ARRAY; i++)
        printf("%d ", array[i]);
    printf("\n");
}

int main(void)
{
    int array[MAX_ARRAY] = {0};
    print(array);
    write(array);
    print(array);
    return 0;
}

Poznámka

Na příkladu vidíme, jakým způsobem jsou vyhodnocovány výrazy v jazyce C. Jedná se o zkrácené vyhodnocování neboli také líné. Tento způsob využívají i jiné programovací jazyky jako C# nebo Java.

int func()
{
    printf("func\n");
    return 0;
}

int main(void)
{
    if ((6 == 5) && (func() == 0)) {}
    return 0;
}

Volání funkce func se nachází v podmínce. Vidíme, že první část podmínky se vyhodnotí na false, zde líné vyhodnocování způsobí, že se druha část podmínky ani nemusí vyhodnocovat, jelikož bude celý výraz false.

K dnešní lekci o rozdělení zdrojového kódu to bude vše. V následující lekci se podíváme na využití rekurze a také na různé použití datových struktur.

Pascal – #5 Cykly se známým počtem opakování

Dnes se naučíme psát cykly v jazyku pascal. Na úvod si řekněme, co to ty cykly jsou. Cyklus nám umožní opakovat určitou část kódu libovolně dlouho. Dnes si řekneme o tzv. cyklech, u kterých známe počet opakování.

Cykly: Obecná synataxe

FOR i:=zacatek TO konec DO
 BEGIN
 Příkaz, který se bude opakovat;
 Příkaz, který se bude opakovat;; 
END;

Teď si to pojďme rozebrat. For je klíčové slovo, které říká, že se jedná o cyklus. Proměnná ‚i‘ tady má roli počítadla. A na začátku cyklu, je nastavena na hodnotu, která se bude při jednotlivých průchodech cyklu navyšovat až do té doby, než nabyde hodnotu uloženou v proměnné konec. Z tohoto kódu je tedy možné okamžitě vyčíst, kolikrát se bude opakovat, protože v prvním řádku v podstatě vidíme interval. Většinou se udává od 1.

Příklad

Aby nám to bylo jasnější, pojďme si to ukázat na jednoduchém příkladu, který nám ukáže, jak funguje počítadlo a co se vlastně v průběhu toho cyklu stane.

program cykly;
uses crt;
var i:integer;
 
begin
 clrscr;
  for i:=1 to 10 do
   begin
      writeln(i);
   end
 repeat until keypressed;
end.

Rozebrání kódu

Jak je již hned zřejmé ze zadání můžeme vidět, že daný cyklus se bude opakovat 10krát jelikož jsme zadali interval od 1 do 10. V příkazové části dá-li se to tak nazvat poté provádíme příkaz Writeln(i), tedy vypisujeme počítadlo. Tento program v podstatě nic nedělá, pouze vypisuje. Hodnota počítadla se zvedá automaticky při každém průchodu cyklu. V praxi to tedy vypadá takto.

Program narazí na slovo For a tím zjistí, že se jedná o cyklus do proměnné i (počítadla) si uloží spodní hodnotu intervalu, a postupuje na další řádek, kde vykoná příslušné příkazy v našem případě, vypíše proměnnou i. Jakmile dojde na konec, vrátí se zase zpět a proměnná i se navýší o hodnotu jedna, porovná ji s koncovou hodnotou intervalu a pokud se nerovná koncové hodnotě, jde znova na příkazovou část cyklu. Toto se opakuje tak dlouho, dokud se hodnota počítadla nerovná koncové hodnotě v té chvíli program opouští cyklus a věnuje se ostatnímu kódu, v našem případě repeat until keypressed; tedy čeká na vstup z klávesnice.

V dalším příkladu si uživatel sám zadá počet opakování. Jedna se tedy pouze o modifikaci předchozího příkladu.

Příklad 2

program cykly2;
uses crt;
var i : integer;
var pocatek : integer;
var konec : integer;
begin
  clrscr;
  write('Zadej cislo pocatek: ');
  readln(pocatek);
  write('Zadej cislo konec: ');
  readln(konec);
    for i:=pocatek to konec do 
    begin
      writeln(i);
    end;
repeat until keypressed;    
end.

V tomto příkladu vidíte, že počet opakování není zadán konstantami ale proměnnými počátek a konec, do kterých uživatel sám zadá čísla a rozhodne si tak počet opakování.

Další možnosti zápisů

Pojďme si ještě ukázat další možnosti zápisu. Například poslední příklad by šel zapsat takto:

for i:=1 to 10 do writeln(i);

Vidíme tedy, že zde chybí struktura begin – end;  sami si zvolte, co pro vás bude lepší. Ale doporučuji používat více řádkovou strukturu z jednoho prostého důvodu ve chvíli, kdy přijdou složitější cykly a bude potřeba napsat více příkazu, bude to mnohem přehlednější. Tento jedno řádkový zápis tedy slouží pro jednoduché příklady.

Kontrolní otázky

Po této lekci by jste měli být schopni zcela s přehledem odpovědět na tyto otázky.

  1. Co je to cyklus a k čemu slouží.
  2. Co je to počítadlo a k čemu slouží.
  3. Jak vypadá obecná syntaxe.

Kontrolní příklad

Napište příklad, který se uživatele zeptá na číslo (počet opakování) a na zprávu. Danou zprávu vypíše píše tolikrát kolik zadal uživatel opakování př. uživatel zadá číslo 4 zpráva se vypíše 4krát..

Závěr

To je z dnešní lekce vše příště se podíváme na podmínky. Pokud Vám není něco jasné ptejte se přímo zde v komentářích.

VBA – 4# Lekce – Zadání vstupních dat – Inputbox

V této lekci si představíme další příkaz Windows. Jedná se o Inputbox, který se využíváme k tomu abychom mohli číst vstupní data od uživatele. Jelikož nejde o nic těžkého pojďme rovnou na příklad.

Příklad:

Sub scitani ()
Dim a as integer
Dim b as integer
Dim vysledek as integer
a = inputbox(“zadej číslo a “)
b = inputbox(“zadej číslo b “)
vysledek= a +b
MsgBox vysledek, vbOKOnly + vbInformation, "Vysledek"
End sub

Teď vysvětlení kódu jediné s čím jsme se zatím nesetkali, je tento řádek:

a = inputbox(“zadej číslo a “)   

areprezentuje proměnnou kam se zadané data uloží.

inputbox– je zavoláni windows příkazu stejně jako msgbox.

(“zadej číslo a “) – toto je popisek uvedený při zobrazení inputbox okna aby uživatel věděl co má zadávat.

Do inputboxu můžeme samozřejmě načítat i jiná data než čísla. Aby, jsme třeba mohli zadávat textová data, musíme proměnným změnit datový typ na string (Dim b as stringsamozřejmě s nimi pak nejde počítat tak jak jsme si ukázali v minulé lekci. Mohou se pouze sčítat logickým operátorem &.

Dnešní lekce byla poměrně krátká a proto si zadáme domácí úkol. Zkuste si přepsat všechny příklady, se kterými jsme se zatím setkali tak abyste v nich použili funkcionality inputboxu.

Závěr

Další lekce se bude zabývat větvením programu pomocí podmínkových příkazu IF.

#6 Vstupní a výstupní funkce

Po delší době zde máme další pokračování kurzu céčka. V této lekci se podíváme na různé možnosti jak načíst data do programu. Ukážeme si také jak data vypisovat pomocí jiných funkcí než z klasické funkce printf, o které jsme se zmínili hned ve druhé lekci našeho kurzu.

Vstupní a výstupní funkce (I/O)

Hodnota Vstup (input) Výstup (output)
znak getchar putchar
řetězec gets puts
formátovaná data scanf printf

 

Všechny tyto funkce se nacházejí v hlavičkovém souboru, který jsme používali doteď a to stdio.h. Pro vstupní funkce se hodnoty vkládají přímo do konzole a potvrdí se enterem. Jejich výzva by měla být zdůrazněna zprávou pomocí výstupní funkce (např.: „Zadejte své jméno: „). Všechny funkce v tabulce si popíšeme.

Getchar a Putchar

Obě tyto funkce pracují pouze s jedním znakem. Pokud bychom funkci getchar dali na vstup nějaké slovo o 2 a více znacích, popřípadě větu, funkce si uloží pouze první znak a zbytek zahodí. Funkce je deklarovaná takto:

int getchar(void)

Vidíme, že funkce nemá žádné vstupní parametry, ale má návratovou hodnotu.

  • úspěšné vyhodnocení vrací vstupní znak
  • neúspěšné vrací konstantu EOF (end of file), tedy hodnotu -1

Funkce getchar je deklarovaná takto:

int putchar(int c);

Funkce má jeden vstupní parametr c od slova character (znak), parametrem je hodnota která se má vypsat na standardní výstup. Putchar dokáže vypsat pouze znaky ohodnocené číslem 0 až 255 (podle ASCII tabulky). Návratová hodnota je znak, který se vypsal. Při neúspěšném výpisu vrací EOF.

char c;
c = getchar();
putchar(c); //vraci zadany znak funkci getchar
putchar(97); //vraci znak 'a'
putchar(97+256); //take vraci znak 'a'

Gets a Puts

Tyto funkce pracují s celými řetězci. Řetězec je posloupnost znaků, v céčku se zapisuje jako pole znaků. Deklarace proměnné typu řetězec se zapíše takto:

char retezec[delka_retezce];

Deklarace obou funkcí vypadají následovně:

char* gets (char*);
int puts (const char*);

Funkce gets načítá řetězec ze standardního vstupu jejím parametrem je řetězec, který musí být předem deklarovaný na určitou délku. Pokud bychom na vstup funkci dali větší řetězec než jak je deklarovaná samotná proměnná, tak se délka proměnné zvětší na požadovanou velikost. Návratová hodnota je vstupní řetězec při úspěšném provedení. Při neúspěšném načtení vrací EOF.

Funkce puts vypisuje řetězec na standardní výstup. Návratová hodnota je nezáporná hodnota při úspěšném vypsání a EOF při neúspěšném.

char string[16];
gets(string);
puts(string);

Scanf a printf

Doteď jsme mohli načíst pouze znak či řetězec, ale pokud bychom chtěli zaimplementovat vstup čísla do programu, musíme použít funkci scanf. Deklarace této funkce:

int scanf(const char *format,…);

Scanf pracuje na stejném principu jako printf, který známe z předchozích lekcí. Může načíst nekonečně mnoho hodnot. Pokud bychom chtěli načíst číslo ze standardního vstupu, kód bude vypadat následovně:

int cislo;
scanf("%d", &cislo);

Aby funkce scanf načetla číslo ze vstupu a následně jej uložila do proměnné cislo, musíme funkci předat adresu proměnné cislo v paměti, nikoliv jeji hodnotu. Pokud bychom chtěli načíst více hodnot, syntaxe bude vypadat obdobně.

int x,y,z;
scanf("%d %d %d", &x, &y, &z);

Na následujícím příkladu vidíme, co udělá formát ve výpisu znaku:

char c = '0';
printf("%c %d\n", c,c);

Pokud vypíšeme proměnnou c (znak ‚0‘) jako číslo vypíše se jeho ASCII kód.

Funkce Rand

Tato funkce je v podstatě vstupní, neboť vrací náhodně vygenerované číslo. Nachází se v hlavičkovém souboru stdlib.h, proto je nutné tento soubor přidat do programu pomocí direktivy #include. Syntaxe vypadá následovně.

nah_cislo = rand() % (horni_hranice-dolni_hranice+1) + dolni_hranice;

Pokud nevyznačíme hranice, v jakých se vygenerované číslo má vyskytovat, použije se výchozí nastavení těchto hodnot. Rozmezí je mezi 0 a 32767. Zápis je pouze takový:

number = rand(); //0 az 32767

Příklady různých rozmezí:

number = rand() % 10; //0 az 9
number = rand() % 10 + 1; //1 az 10
number = rand() % 113 + 1900; // 1900 az 2012

Pokud si program, který generuje číslo, spustíte vícekrát za sebou a přitom nezměníte syntaxi, zjistíte, že se generují pořád stejné čísla. Aby se při každém spuštění generovaly nové čísla, použijeme příkaz z knihovny time.h.

srand (time(NULL));

Celý program nyní může vypadat takto:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    srand (time(NULL));
    int n = 10;
    int horni, dolni;
    int number;

    printf("Zadej horni mez: ");
    scanf("%d", &horni);
    printf("Zadej dolni mez: ");
    scanf("%d", &dolni);

    printf("%d cisel vygenerovanych v rozmezi %d az %d (vcetne)\n",n, dolni, horni);
    for (int i = 0; i < n; i++)
    {
        number = rand() % (horni-dolni+1) + dolni;
        printf("%d\n", number);
    }

    return 0;
}

Data lze načíst také pomocí souboru, ale kompletní práci se soubory si ukážeme v některé z následujících lekcí. Ke vstupním a výstupním funkcím to bude vše. Příště se podíváme jak rozdělit zdrojový kód do více pod částí.

Pascal – #4 Práce s datovými typy, textové funkce

V dnešní lekci si ukážeme použití proměnných a základní práci s datovými typy k tomuto si také představíme některé textové funkce. Nejprve si však osvětlíme pár věcí, které nám to umožní.

Začneme tím, že si řekneme, jak jsme schopni uložit data do proměnné. Docílíme toho kombinací znaků := aby jste lépe pochopili vypadá to takhle promenna:=hodnota (například číslo, znak, řetězec znaků, atd. záleží jak jsme si proměnnou deklarovali, čili jaký očekává datový typ). Kompletně si to ukážeme se všemi datovými typy na následujícím příkladu. V tomto příkladu nic nevypisujeme pouze přiřazujeme hodnoty nebuďte tedy překvapení pokud po jeho spuštění neuvidíte žádný vystup. Je to čistě pro procvičení a aby jste pochopili užití datových typu a rozdíly mezi nimi.

program dat_typy;

uses crt;
var cele_cislo : integer;
var desetine_cislo : real;
var a : boolean;
var znak : char;
var veta : string;

Begin

       cele_cislo:=5;
       desetine_cislo:=4.5;
       a:=TRUE;
       znak:='A';
       veta:='ahoj toto je muj dalsi program';

end.

Načítání vstupních dat funkce Readln

Dále se naučíme načítat vstupní data od uživatele. Využijeme k tomu funkci Readln. Tato funkce očekává jeden argument, kterým bude název proměnné, do které má načtená data uložit. Syntaxe vypadá takto Readln(promenna);  Za chodu programu to tedy vypadá takto. Blikající kurzor čeká na zadaní dat jakmile k tomu dojde uloží Vámi zadané vstupní data do promenné. Musíme si však dát opět pozor aby jsme zadávali data, která se shodují s datovým typem proměnné do které se bude ukládat tzn. nemohu na vstupu zadat číslo a chtít pro funkci Readln aby ho uložila do proměnné string(textový řetězec) toto by zahlásilo chybu.

Dále pak bude možnost vypsat si v pascalu znak na příslušné pozici v textu. Uděláme to následovně. Předpokládejme, že v proměnné znaky máme uložen text „ahoj“, potom tedy tento řádek Writeln(znaky[1]); by nám vypsal znak ‘a’ jinými slovy vypíše první znak z proměnné „znaky“. Na následujícím příkladu si vše ukážeme praktický i s použitím funkce Readln.

Program znak;
uses crt.

var veta : string;
var pozice : byte;
var vysledek:char;

begin

  Writeln('zadej libovolnou větu');
  Readln(veta);
  Writeln('zadej pozici kterou chceš vypsat');
  Readln(pozice);
  vysledek:=veta[pozice];
  Writeln(vysledek);
repeat until keypressed;
end.

Funkce ord

Další co potřebujeme vědět, jsou funkce ord a chr. Funkce ord očekává jeden argument v podobě jednoho znaku a na svém výstupu vrací jeho hodnotu v ASCII tabulce. Pokud si toto aplikujeme znovu na naši ukázku, vypadalo by to takto:

Writeln(ord(znaky[1])) jelikož první znak našeho textu je písmenko ‚a‘ bude tedy funkce ord převádět tento znak na jeho hodnotu. Hodnota ‚a‘ je 97. Zde naleznete veškeré znaky a jejich hodnoty. http://www.theasciicode.com.ar/

Funkce chr

Funkce chr dělá přesný opak očekává jeden argument v podobě číselné hodnoty a na svém výstupu vrátí znak odpovídající zadané hodnotě. Na příkladu by vypadlo následovně. Writeln(chr(97)) toto by vypsalo na obrazovku ‚a‘.

Délka textového řetězce funkce lenght

Pojďme si ukázat ještě funkci lenght. V překladu by se tato funkce jmenovala ‚délka‘. Jak již tedy název napovídá, funkce bude vracet délku zadaného řetězce. Funkce očekává jediný argument v podobě řetězce znaků. Syntaxe je a:=length(retezec); vysvětlení – do proměnné ‚a‘ se uloží délka řetězce.  Pokud chceme vypsat na obrazovku, použijeme Writeln(length(retezec));

Příklad

Pojďme si to tedy ukázat na příkladu. Uživatel zadá libovolný znak a poté zadá číslo od 1 do 10, o které se posune hodnota znaku. Výsledný znak se poté vypíše. Jedná se tedy o jakýsi super jednoduchý šifrovací prográmek. Lépe to pochopíme při pohledu na zdrojový kód.

program sifra;

 uses crt;
 type cisla = 1..10;
 var posun: cisla;
 var vstup: char;
 vystup: char;
 hodnota:byte;
 begin clrscr;
 write('Vlozte znak k šifrování');
 readln(vstup);
 write('Vlozte posun v rozsahu od 1 do 10: ');
 readln(posun);
 hodnota:=ord(vstup) + posun vystup:= chr(hodnota);
 writeln('Znak ', vstup, ' posunuty o ', posun, ' znaku je ', vystup);
 repeat until keypressed;
 end.

Abychom si kód mohli lépe vysvětlit, předpokládejme, že uživatel zadal znak ‚a‘ a posun nastavil na hodnotu 3. V této chvíli nás tedy čeká řádek hodnota:=ord(vstup) + posun zde funkce ord očekává jeden argument, dostane se mu písmene ‚a‘, které převede na číslo 97, které potom sečte s číslem 3 výsledek tohoto, se uloží do proměnné hodnota.  Na dalším řádku vystup:= chr(hodnota); očekává funkce chr jeden číselný parametr k převedení na znak, dostane se mu číslo 100, které se rovná písmenku d, to celé se uloží do proměnné výstup.

Tyto dva řádky by šly nahradit jedním, který by vypadal takto, vystup:= chr(ord(vstup) + posun);

Avšak pro přehlednost jsem to raději rozepsal do dvou řádků, aby byla jasně vidět posloupnost jednotlivých kroků a bylo to lépe představitelné.

Příklad 2

Pojďme si ukázat další příklad. Tentokrát se bude jednat o primitivní kalkulačku.  Zadáme programu dvě čísla. Jako výsledek nám vypíše jejich součet rozdíl podíl a součin.

program kalkulacka;
uses crt;
var x: byte;
y: byte;
soucet: byte;
rozdil: byte;
soucin: byte;
podil: real;
begin clrscr;
write('Zadejte hodnotu promenne x: ');
readln(x);
write('Zadejte hodnotu promenne y: ');
readln(y);
z1:= x + y;
z2:= x - y;
z3:= x * y;
z4:= x / y;
writeln('Soucet hodnot: ', soucet);
writeln('Rozdil hodnot: ', rozdil);
writeln('Soucet hodnot: ', soucet);
writeln('Podil hodnot: ', podil:5:2); //uprava poctu znaku a desetiných míst
repeat until keypressed;
end.

Zde se jedná o v podstatě jednoduchý příklad. Jediné co si vysvětlíme je výpis proměnné podíl, kde nalezneme tento řádek. writeln(‚Podil hodnot: ‚, podil:5:2); jak si můžete všimnout za proměnnou podíl jsou ještě dvě hodnoty oddělené znakem ‘:‘ jelikož se jedná o typ real,který obsahuje desetinou čárkou tak mu určíme kolik má vypsat čísel celkově to je to první číslo a kolik čísel za desetinou čárkou to je to druhé číslo. Můžete si vyzkoušet, jak by to vypadalo bez tohoto.

Závěr

V této lekci jsme si ukázali začátky práce s textem a čísly. Byla to trochu více praktická lekce také proto, abychom si zažili syntaxi jazyka a vývojové prostředí. Měli by jste tedy s přehledem zvládat zadávání dat od uživatele čili funkci READLN a jejich uložení do proměnné, dále pak funkci ord, str a lenght a v neposlední řadě také vypsat znak na určité pozici v textu. Měli by jste také pochopit princip datových typů tzn. vědět jaké data vstupují a přizpůsobit tomu proměnné.

V sekci ke stažení bude také dostupný ještě jeden program k dalšímu procvičování a ukrácení času při čekání na další lekci, která se bude zabývat tentokrát cykly.

#5 Pole a ukazatel

V dnešním článku se podíváme na velice důležitou část v céčku, ukazatel nebo také pointer. Jak ukazatel funguje, si ukážeme hned na několika příkladech. S ukazateli se budeme potýkat i v dalších lekcích, takže se pokusím co nejlépe vysvětlit jak s nimi pracovat. V druhé části si ukážeme využití pole.

Ukazatel

Ukazatele uchovávají adresu na nějaké místo v paměti. Při deklaraci proměnné typu ukazatel se specifikuje i datový typ, tento typ je totožný s hodnotou místa paměti, na kterou ukazuje, tzn. že ukazuje na hodnotu určitého datového typu.

Deklarace ukazatele na datový typ:

int* nazev_ukazatele

Operátor reference (&)

Vrací adresu (pozici v paměti) svého parametru, následná hodnota lze přiřadit do ukazatele.

int cislo = 5;
int*pCislo = &cislo;

Konvence o pojmenovávání ukazatelů: Název proměnné typu ukazatel se skládá z písmene p (od slova pointer) a z názvu proměnné (bude začínat velkým písmenem) na kterou ukazuje.

Operátor dereference (*)

Vrací hodnotu na určitém místě paměti, adresa toho místa je uložena v argumentu.

Nyní si ukážeme jak správně vypsat hodnotu ukazatele. Použijeme deklarace, které jsou znázorněny na obrázku.

printf("%d\n", *pCislo); //vypise hodnotu promenne cislo, tedy 5
printf("%d\n", pCislo); //vypise adresu v pameti promenne cislo

Více ukazatelů může ukazovat na stejné místo v paměti. Následující zápis je správný pokud používáme předešlé deklarace.

int* pCislo2 = &cislo;

Pole

Jedná se o skupinu proměnných, které mají stejný datový typ a jsou označený stejným názvem. Pro přístup k jednotlivým prvkům v poli se využívají tzv. indexy, kterými jsou všechny prvky v poli identifikovány. V paměti je pole uloženo souvisle.

Jazyk C nehlídá meze polí, z důvodu rychlosti, proto pokud budete zapisovat mimo pole, obvykle to vede k chybě a program spadne.

Jednorozměrné pole

  • K prvkům pole se přistupuje pomocí operátoru [] (hranaté závorky)
  • Indexy prvků začínají vždy od nuly.

Obecná deklarace jednorozměrného pole:

datovy_typ nazevpole[velikost_pole]; //velikost_pole urcuje pocet prvku v poli.

Pokud bychom chtěli již při deklaraci proměnné inicializovat i jednotlivé prvky pole, použijeme tento zápis:

int array[5] = {8,6,9,-1,25};

Jestli použijeme takto plně inicializované pole, je možné vynechat hodnotu, která určuje velikost pole, velikost se automaticky zjistí z počtu inicializovaných prvků.

Pokud neinicializujeme všechny prvky v poli, ale např. pouze 2, tak se ostatní prvky nastaví na hodnotu 0. Pokud bychom chtěli mít celé pole vynulované, použijeme tento zápis:

int array[5] = {0};

Pro zápis konkrétního prvku v poli použijeme následující zápis, ostatní neinicializované hodnoty se opět nastaví na hodnotu 0.

int array[5] = {[1] = 5, [4] = 10};

Inicializace prvku pole se většinou neprovádí ihned při samotné deklaraci pole, ale později v kódu na základě vstupu ze souboru či z klávesnice. Pro procházení prvku se nejlépe použije cyklus. Aritmetika nad prvcích pole je stejná jako u obycejné proměnné.

int array[10];
for (int i = 0; i < 10; i++)
    array[i] = i; //zapis do pole

for (int i = 0; i < 10; i++)
    printf("%d\n", array[i]); //vypis prvku z pole

Vícerozměrné pole

  • Deklarace je stejná jako u jednorozměrného pole, pouze za názvem pole tolik určení velikosti, kolik chceme rozměru. Velikosti se zapisují za sebou, opět do hranatých závorek.
  • Přístup k prvkům je stejný, opět musíme uvést tolik hodnot v hranatých závorkách, kolik je rozměrů.

Deklarace dvourozměrného pole, jedná se v podstatě o matici prvků:

int array[2][3];
int array2D[2][3];
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        array2D[i][j] = i + j;

for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        printf("%d\n", array2D[i][j]);

Nejčastěji z vícerozměrných polí se používá právě matice. Jednoduší je ale realizovat dvourozměrné pole jako jednorozměrné a o správný zápis do pole řešit později v programu. Deklarace je jednoduchá, stačí provést násobení mezi oběma rozměry. Přístup k prvku je o něco složitější:

array1D[radek * pocet_sloupcu + sloupec];

Převod naší matice 2 x 3 na jednorozměrné pole.

int array1D[2*3];
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        array1D[i * 3 + j] = i + j;

for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        printf("%d\n", array1D[i * 3 + j]);

Pole a ukazatel

Vztah mezi ukazateli a poli je velmi blízky, totiž pole je možno realizovat pomoci ukazatele, tento způsob je rychlejší ale asi o trošku hůř pochopitelný.

    int array[10];
    for (int i = 0; i < 10; i++)
        array[i] = i;

    int* pArray = array; //pArray ukazuje na prvni prvek v poli

    printf("%d\n", *pArray); //vypise prvni prvek
    printf("%d\n", *(pArray + 5));

    pArray++; //posun na prvek nasledujici
    //*pArray++; //spatny posun prvku (warning)
    *pArray = -20; // prirazeni hodnoty do aktualniho prvku
    *(pArray + 3) = -10; // prirazeni hodnoty do aktualniho prvku + 3

    printf("Vypis pole: ");
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", array[i]); //vypis vsech prvku
    }

    pArray++;
    pArray++;
    printf("\n%d\n", pArray - array); //vypise pocet prvku mezi zacatkem pole a aktualnim prvkem

K dnešní lekci to bude vše doufám, že jsem vám dostatečně vysvětlil práci s ukazateli. Příště se podíváme na různé funkce vstupu.

Pascal #3 Proměnná a datové typy

Proměnná

Začneme tím, že si vysvětlíme co je to proměnná. Proměnná je v podstatě místo kam si náš program ukládá nějaké data, ať už to jsou mezivýsledky, výsledky nebo hodnoty čekající na zpracování. Chápejme to tedy, jako jistý prostor kam jsme schopni ukládat data, následně k nim přistupovat a dále s nimi pracovat.

Datové typy

již tedy víme, že do proměnných můžeme ukládat nějaké data ale program, potřebuje vědět přesně, jaká data budeme ukládat, a v této chvíli přichází na scénu datové typy. V zásadě rozlišujeme tři hlavní typy

  1. Textové pod tímto si představíme jakýkoliv text nebo jeden znak.
  2. Číselné jakýkoliv údaj, se kterým jsme schopni počítat.
  3. Logické, které nabývají jenom logických hodnot TRUE nebo FALSE

Vše co jsme si doposud řekli, využijeme u deklarace proměnné. Deklaraci chápej jako vyhradit prostor. V pascalu to vypadá následovně: var nazev_promenne : prislušny_datový_typ; Na tomto řádku jsme programu řekli vše, co potřebuje. Slovně by to šlo říci nějak takhle. Vyhraď si prostor pro proměnnou nazev_promenne do které budu ukládat příslušný_datový_typ.

Jinými slovy „var“ je klíčové slovo tak aby kompilátor věděl, že deklarujete (zavádíte) novou proměnnou. Druhé slovo je „nazev“ je název proměnné může byt libovolný (pro pozdější přehlednost programu je doporučeno využívat vždy jednoznačné informativní názvy proměnných) za dvojtečkou poté následuje datový typ zjednodušeně řečeno jaké data se mohou do proměnné uložit více v následující kapitole. Abychom si to mohli napsat víc konkrétněji  pojďme se podívat na jednotlivé datové typy a jejich charakteristiky.

TEXTOVÉ datové typy

Zde se řadí typy, kde zadáváme jakékoliv znaky z ASCII tabulky. Tedy i čísla není možno však s nimi počítat, program je bere jen jako textový řetězec. Textový řetězec se v pascalu ohraničuje apostrofy ‘příklad textového řetězce !! ?? 1234‘

Rozlišujeme zde dva typy

  •     CHAR zde můžeme uložit jen a pouze jeden jediný znak. Příklad ‚A‘
  •     STRING zde můžeme uložit textový řetězec o maximální délce 255 znaků. Příklad ‚příklad textového řetězce !! ?? 1234‘

ČÍSELÉ datové typy

Do těchto datových typů budeme ukládat údaje, se kterými budeme počítat. Dělí se na:

Celočíselné (ukládáme pouze celá čísla)

  •  Byte jeho rozsah je od 0 do 255
  •  Shortint jeho rozsah je od -128 do 127
  •  Word jeho rozsah je od 0 do 65535
  •  Integer jeho rozsah je od -32768 do 32767
  •  Longint jeho rozsah je od -2147483648 do 2147483647
  •  Comp jeho rozsah je od -263+1  do 263-1

Neceločíselné (možno ukládat i čísla s desetinnou čárkou)

  •  Real jeho rozsah je od 2,9*10-39 do 1,7*1038
  •  Single jeho rozsah je od 1,5*10-45 do 3,4*1038
  •  Double jeho rozsah je od 5,0*10-324 do 1,7*10308
  •  Extended jeho rozsah je od 3,4*10-4932 do  1,1*104932

LOGICKÉ datové typy.

Do tohoto typu dat můžeme ukládat hodnoty pouze dvou stavu True a False respektive 1 a 0. Mají pouze jeden typ a tím je BOOLEAN.

Tímto jsme si tedy ukázali všechny dostupné datové typy. Teď malý příklad toho jak by to mohlo vypadat. Samozřejmě by se daly použít i jiné typy u celého čísla například typ byte. Avšak pro ukázku nám postačí:

  •   Proměnná, do které chceme uložit text  var a :string;
  •   Proměnná, do které chceme uložit znak var a :char;
  •   Proměnná, do které chceme uložit celé číslo var a:integer;
  •   Proměnná, do které chceme uložit číslo s desetinou čárkou var a :double;
  •   Proměnná, do které chceme uložit pravdivostní hodnotu var a :boolean;

V pascalu se také můžeme setkat s vlastním datovým typem interval. Proměnná v tomto datovém typu obsahuje námi již nadefinovaná data (tedy buď číslo znak, nebo logický datový typ) avšak pouze v určitém intervalu. Obecný příklad vypadá následovně.

Type x= min..max;

Var a : x;

na prvním řádku jsme si deklarovali vlastní datový typ interval. Na druhém poté deklarujeme novou proměnnou, která bude nabírat hodnot námi vytvořeného datového typu. V praxi to může vypadat takto

Type rozsah = 1..100;

Var cislo : rozsah;

Nebo

Type rozsah = ’a‘ .. ’g‘;

Var znak : rozsah;

Vidíme tedy, že do proměnné číslo můžeme zapsat čísla pouze od 1 do 100 a do proměnné pouze znaky od ‚a‘ do ‚g‘.

Ordinalita

Za zmínku také ještě stojí říct si, jaké datové typy jsou ordinální. Pojďme však od začátku a nejdříve si zaveďme pojem ordinální. Je to ve své podstatě velice jednoduché.

Ordinální prvek je takový, který má svého předchůdce a následovníka. Ordinální jsou tedy celočíselné datové typy, u kterých můžeme z jistou říct, co předchází například před číslem 10 a jaké číslo stojí za ním. Jelikož se jedná o celočíselný datový typ, je jasné, že předchůdce je 9 a následovník je 11.

Kdybychom měli to samé číslo v datovém typu neceločíselném, nemůžeme s určitostí tvrdit jaké má předchůdce a následovníky. Protože po 10 může následovat 10.1 nebo například 10.567. Neceločíselné typy jsou tedy neordinální.  Datový typ Char je také ordinální protože všichni víme, že například před písmenkem ‚B‘ přijde na řadu ‚A‘ a následovník ‚B‘ je zase ‚C‘. Posledním ordinálním typem je typ boolean jelikož nabývá pouze dvou hodnot je to jednoduché. Když nabude 1 je jasné že předchůdce je 0 a naopak.

Příště si projdeme pár příkladu týkajících se právě datových typu a ordinálních hodnot.

 

#4 Řídící Struktury

V této lekci, v pořadí 4. se podíváme na řídící struktury. Patří zde podmíněné příkazy a cykly. Zařadíme zde i přepínač (příkaz switch), jeho využití je minimální. Použití jednotlivých struktur si znázorníme na příkladech.

Podmínky

Podmínka s IF

Podmíněné výrazy se tvoří pomocí klíčového slova if. Je možné použít i else ale není to nutnost.

Obecný tvar:

if (podminka)
{
	prikazy
}
else
{
	Prikazy
}

Syntaxe dovoluje zapsat podmínku i bez složených závorek, které ohraničují příkazy jak pro splněnou tak pro nesplněnou podmínku.

int vysledek = 0;

if (5 > 6)
    vysledek += 10;
    vysledek += 15;

printf("Vysledek: %d\n", vysledek);

Jak bude vypadat výpis toho programu?

Vysledek: 15

Pokud nepoužíváme složené závorky, tak ke splněné či nesplněné podmínce přiřadí pouze první příkaz. V tomto programu se podmínka nesplní. Přiřazení +10 se neprovede a else větev neexistuje. Následná operace +15 již není součásti podmíněného příkazu a je provedena.

Na následujícím příkladu vidíme použití více větví:

    
int den = 7; //predpokladejme prirazeni v rozmezi 1 až 7

if (den == 6)
    printf("je vikend\n");
else if (den == 7)
    printf("je vikend\n");
else
    printf("je pracovni den\n");

Vidíme ale, že první 2 větve mají stejný výstup je možné je spojit do jedné za použití správného operátoru:

if (den == 6 || den == 7)
    printf("je vikend\n");
else
    printf("je pracovni den\n");

Příkaz switch

Pokud máme podmínku, která obsahuje mnoho větví, je jednoduší a přehlednější použít příkaz switch.

Obecný tvar:

switch(celociselna_promenna)
{
	case konst_vyraz_1 : prikazy_1;
	case konst_vyraz_n : prikazy_n;
	default : prikazy_vychozi;
}

Následující program vypisuje slovně den v týdnu. Každý den je charakterizovaný číslem, zadán v proměnné den. Klauzule default se provede, pokud výčet neobsahuje konkrétní hodnotu, ale tento příkaz není povinný.

int den = 5;

switch(den)
{
    case 1 : printf("pondeli\n");break;
    case 2 : printf("utery\n");break;
    case 3 : printf("streda\n");break;
    case 4 : printf("ctvrtek\n");break;
    case 5 : printf("patek\n");break;
    case 6 : printf("sobota\n");break;
    case 7 : printf("nedele\n");break;
    default : printf("neznamy den\n");break;
}

Tento příklad obsahuje stejné zadání, jako příklad u podmínky s if, abyste mohli srovnat syntaxi.

int den = 5; //opet predpokladame ze prirazeni je v rozmezi 1 až 7
switch (den)
{
    case 6 :
    case 7 :
    printf("je vikend\n"); break;
    default : printf("je pracovni den\n"); break;
}

Cykly

Cyklus musí vždy obsahovat podmínku, podle které se cyklus ukončí. V těle cyklu musí být výraz, který souvisí s ukončovací podmínkou cyklu. Na základě výpočtu tohoto výrazu, se podmínka v určitém kroku nesplní a dojde k ukončení cyklu. V jazyce C existují 2 typy cyklů. Jako u podmínek i v cyklech je možné nevyužít složené závorky, ale cyklus se bude vztahovat pouze k prvnímu příkazu (posloupnost znaků oddělená nejbližším středníkem).

1. For

Obecný tvar:

for (pocatecni_hodnota;podminka;inkrementace)
{
	prikazy
}

Zde vidíme základní použití cyklu for. Program vypisuje jednotkovou matici, za pomoci 2 cyklu.

#include <stdio.h>

int main(void)
{
    unsigned char rozmer = 6; //rozmer matice

    for (int i = 0; i < rozmer; i++)
    {
        for (int j = 0; j < rozmer; j++)
        {
            if (i == j)
                printf("1 "); //vypisuje 1 na hlavni diagonale
            else
                printf("0 ");
        }
        printf("\n");
    }

    return 0;
}

Tento program vypočítává faktoriál ze zadaného čísla (proměnná cislo), je vhodné si na tomto programu vyzkoušet debugger. Pokud neumíte s debuggerem v Qt Creatoru pracovat, zde je návod k použití.

#include <stdio.h>

int main(void)
{
    unsigned int cislo = 6;
    unsigned int faktorial = 1;

    for (unsigned int i = cislo; i > 0; i--)
    {
        faktorial *= i;
    }

    printf("Vysledek: %u\n", faktorial);
    return 0;
}

Tento ukázkový příklad zobrazuje nekonečný cyklus. Ukončení běhu programu v konzoli se provede pomocí klávesové zkratky CTRL + C.

for (int i = 0; i < 1; i++)
{
    i = 0; //ridici promenna je vynulovana a podminka cyklu je s kazdou iteraci cyklu splnena
    printf("%d", i);
}

2. While

Tento cyklus může být dvojího typu, záleží jestli je podmínka cyklu na začátku nebo na konci.

Obecný tvar s podmínkou na začátku:

while (podminka)
{
	prikazy
}

Obecný tvar s podmínkou na konci:

Do
{
	Prikazy
} while (podminka);

Na tomto triviálním příkladu vidíme rozdíly mezi oběma typy cyklu while:

do
{
    printf("Cyklus while s podminkou na kocni\n");
} while(1 == 2);

while(1 == 2)
{
    printf("Cyklus while s podminkou na zacatku\n");
}

Zde můžeme srovnat syntaxe obou dvou typu cyklu (for i while)

#include <stdio.h>

int main(void)
{
    printf("Zde je vypis cyklu for\n");
    for (int i = 0; i < 3; i++) //v tomto radku vidime inicializaci pocatecni hodnoty, podminku i inkrementaci 
    {
        printf("for: %d\n", i);
    }

    printf("\nZde je vypis cyklu while\n");
    int j = 0; //zde je inicializace pocatecni hodnoty
    while (j < 3) //zde je podminka cyklu
    {
        printf("while: %d\n", j);
        j++; // zde je inkrementace
    }

    return 0;
}

Pomocné příkazy v řídících strukturách

break

S tímto příkazem jsme se již setkali u switch, kde byl použit u každého výčtu. Pokud by příkaz break nebyl pouzit ani u jednoho výčtu, příkaz switch by se nechoval jako podmíněný výraz a byl by naprosto zbytečný. Pokud upravíme příklad, který jsme si uvedli právě u příkazu switch, tak že odstraníme všechny příkazy break, můžeme pozorovat změnu ve výpisu pro všechny hodnoty 1 až 7.

Obecně příkaz break předčasně ukončuje cykly for či while. V daném programu se postoupí na příkaz, který se nachází bezprostředně za tímto cyklem. Použití si znázorníme na ukázkovém příkladu:

#include <stdio.h>

int main(void)
{
    unsigned char cislo = 250;
    for (int i = 1; i < 100; i++)
    {
        cislo++;
        printf("%d. iterace cyklu | cislo = %d\n", i, cislo);
        if (cislo == 255) //pokud dojde k preteceni datoveho typu, cyklus se zastavi
            break;
    }

    return 0;
}

continue

Tento příkaz funguje podobně jako break, s tím rozdílem, že neukončí celý cyklus, ale pouze právě prováděnou iteraci.

goto

Příkaz provede přesun na určitý řádek kódu, který je označen tzv. štítkem. Tento štítek musí mít stejný název jak pro označení řádku tak jako hodnota příkazu goto, aby příkaz fungoval správně

goto stitek
...
stitek : prikazy

Tento příkaz je možné použít i ke zkonstruování cyklu:

int i = 0;

iterace : if (i < 10)
{
    printf("%d. iterace\n",i);
    i++;
    goto iterace;
}

Všechny tyto 3 příkazy je možné nahradit, je vhodné je používat co nejméně a příkaz break používat pouze u switch.

Poznámka

Nepleťte si operátory = a == první slouží k přiřazení a druhý porovnává 2 hodnoty.

To je vše k dnešní lekci o řídících strukturách v jazyce C. Příště se podíváme na využití polí a také na ukazatele.

Pascal – #2 Obecná struktura, první příklad

V této lekci si ukážeme, obecnou strukturu jazyka Pascal. Podíváme se také na pár syntaktických pravidel. Vše budeme demonstrovat na jednoduchém příkladu. Tak tedy začneme, spustíme si naše vývojové prostředí, které jsme si nainstalovali v minulé lekci a přepíšeme následující příklad.

První příklad

Program ahoj;
 Uses crt;
 Begin Clrscr;
 Writeln(‘ahoj muj první vypis na obrazovku‘);
 Repeat until keypressed;
 End.

Kompilace

Ještě před tím než si daný program popíšeme tak si ukážeme jak program spustít. Nejdříve musíme příklad zkompilovat. Pod pojmem kompilace si představíme přeložení. Celý tento úkon děláme proto, abychom přeložili námi napsané řádky v jazyce pascal do jazyku, který bude srozumitelný našemu počítači (tzn. Překlad do strojového kódu) aby mohl dané příkazy vykonat a vrátit nám požadovaný výsledek. Kompilaci provedeme tak, že klikneme v menu na položku ‚compile‘ -> ‚build‘ pokud jsme byli úspěšní a compilator nenašel žádnou syntaktickou chybu, objeví se Vám tabulka informací čekající na potvrzení jakoukoliv klávesou. Nyní již můžeme s klidem spustit náš mini program přes položku ‚run‘ -> ‚run‘. Nyní by se Vám měl objevit výpis na obrazovku.

Popis Kódu

A teď jak to tedy celé vlastně funguje. Každý program napsaný v pascalu začíná příkazem Program a následuje jeho název. K tomuto se vztahují jistá omezení :

  • nesmí začínat číslem
  • nesmí obsahovat mezery
  • musí být ukončet středníkem
  • nesmí se shodovat s žádným interním příkazem jazyku Pascal například jako název programu nesmíme zvolit název Readln.

Na druhém řádku vidíme uses crt; v příkazu USES se uvádí seznam jednotek (knihoven), se kterými má překladač programu(compilator) pracovat při sestavování programu. Toto si zatím představíme tak, že pokud potřebujeme v programu použít výpis na obrazovku (jakože budeme potřebovat téměř vždy) napíšeme uses crt; Prozatím si s tímto nebudeme nijak lámat hlavu.  Jen pro úplnost uvádím ostatní základní jednotky(knihovny)

  • CRT – řízení systému zobrazení, vstupu z klávesnice, práce s okny
  • DOS – komunikace mezi aplikačním programem a OS
  • SYSTEM  – standardní procedury a funkce
  • GRAPH – grafické možnosti
  • Další : STRINGS, OVERLAY, PRINTER

Příkaz BEGIN ohraničuje samotné tělo programu. A píšeme ho vždy.

Příkaz CLRSCR; nám tzv. vyčistí obrazovku bude tam tedy jen ta naše zpráva. Na funkčnost programu to nemá vliv, ale vypsaná data na obrazovce jsou potom přehlednější. Schválně si zkuste příklad bez tohoto příkazu a uvidíte rozdíly ve výstupu.

Na dalším řádku se již dostáváme k samotnému výpisu. Ten nám zajišťuje příkaz Writeln. Tento příkaz znamená, vypiš zprávu na obrazovku. Avšak požaduje argument v podobě „co mám vypsat“ vždy tedy musíme do závorky napsat buď proměnnou, nebo textový řetězec ohraničený apostrofy (ty vypadají takhle ‚). Toto musíme udělat aby měl Writeln vůbec co vypisovat.C

Další řádek je jakýsi cyklus a vypadá takto repeat until keypressed; Toto však budeme probírat až pár kapitol dále. Nyní Vám stačí vědět, že pozdrží Vámi vypsanou zprávu na obrazovce do té doby, než zmáčknete libovolnou klávesu. Program by fungoval i bez tohoto avšak provedl by se na pozadí, respektive nebyla by vidět Vámi vypsaná zpráva. Znovu si to můžete vyzkoušet a tento řádek umazat a pozorovat rozdíl.

Poslední příkaz je příkaz end. který ukončuje celý program.

Jak jste si již mohli všimnout, za každým příkazem se musí udělat středník až na výjimku begin kde není nic a end na konci programu kde se uvádí závěrečná tečka. Těchto vyjímek je však více my si je budeme ukazovat postupně jak na ně budeme narážet.

Samostatná práce

Za domácí úkol si zkuste náš program napsat bez příkazu clrscr; a poté bez repeat until keypressed;

Závěr

Toto je tečka za naší první lekci příště se podíváme na proměnné a datové typy. Po této lekci by jste tedy měli umět základní strukturu programu a znát příkaz writeln, který budeme používat v každé další lekci.