VBA – 6# Lekce – Textové funkce

V dnešní lekci se podíváme na práci s textem. Bude se jednat o úpravy textu vyhledávání znaků zjišťování délky řetězce pomocí zabudovaných funkcí, které nalezneme ve VBA. Abychom mohli efektivně pracovat s textovými řetězci, potřebujeme znát právě tyto funkce. Aby se nám lépe demonstrovaly jednotlivé funkce, uvažujme, že máme proměnnou txt, ve které máme uložen text ‚abeceda je veda‘. V kódu zapsáno takto txt=‘abeceda je veda‘. Nyní se již vrhněme na jednotlivé funkce

Funkce Len

nám zjistí počet znaků v textu. Jako jediný parametr požaduje právě text, který má spočítat. Text může být reprezentován jak proměnnou, tak samotným textem v uvozovkách.

Ukázka syntaxe:

Delka=len(txt)
Msgbox(len(txt))

V prvním řádku jde o uložení délky proměnné txt do proměnné délka. Na druhém řádku, dojde k vypsání délky v naše případě se vypíše číslo 15. Je nutné mít na paměti, že do délky textového řetězce se započítávají jak mezery, tak znaménka tak čísla. K lepšímu zapamatování této funkce uvedu, že len je zkrácenina slova length, které v překladu z angličtiny znamená délka ;).

Instr

jedná se o vyhledávací funkci. Zde už se setkáváme s mírně složitějším zapsáním.  Tato fůnkce vyžaduje hned tři parametry, ale není se čeho bát, všechny tři vyplývají z logiky této funkce. Nejdříve tedy musíme zadat startovní pozici to je pozice, na které se začne vyhledávat, jako druhý argument zadáme, kde se má hledat, čili v jakém textovém řetězci v našem modelovém příkladu to bude proměnná txt, jako poslední chce funkce znát hledaný řetězec, který musí být uveden v uvozovkách, hledat můžeme jak jednotlivé znaky, tak i více znaku najednou ba do konce i celé věty podmínka je však, že musí být ohraničeno uvozovkami.

Ukázka syntaxe

Msgbox Instr(1,txt,“j“)

Vidíme tedy, že funkce bude vyhledávat od první pozice v proměnné txt a bude hledat znak „j“.  V našem případě, tedy vrátí hodnotu 9. Pokud bychom hledali více znaků, funkce vrátí vždy pozici, na které hledaný řetězec začíná. Pokud bychom hledali slovní spojení „je“ funkce vrátí opět 9.

Left

Při použití této funkce dojde k vrácení jenom určité části textu. Konkretně vrací zadaný počet znaků od začátku námi zvoleného textového řetězce. Z čeho vyplývá, že požaduje dva parametry textový řetězec odkud bude vracet znaky a počet znaků.

Ukázka syntaxe

Msgbox left(txt,7)
Kus_textu=left(text,7)

S takto zadanou funkcí dostaneme na výsledku slovo „abeceda“. Na druhém řádku se nic nevypisuje, pouze uložíme výstup z funkce do nové proměnné. Je třeba si uvědomit, že funkce nic nemění, pouze vypisuje pokud tedy chceme pracovat jen s určitou části, musíme si ji uložit do jiné proměnné, jako jsem naznačil na druhém řádku.

Right 

tato funkce je zcela totožná jako výše uvedená left jediné co se mění je, že tato funkce zobrazuje znaky zprava nebo chcete-li od konce textového řetězce syntaxe je zcela stejná. Pomocí této funkce můžeme zjistit také velice jednoduše poslední znak v textu.

Ukázka syntaxe

Msgbox right(txt,7)

Toto nám vypíše retězec „je veda“

Mid

nám umožní zobrazit určitou část textu. Vyžaduje k tomu tři parametry, první z nich je jak už jste si asi zvykli, textový řetězec odkud budeme část vybírat v našem případě tedy opět txt. Jako druhý parametr chce funkce znát číslo, které reprezentuje pozici, odkud má začít brát znaky a jako poslední chce číslo, které zastupuje počet zobrazených znaků.

Ukázka syntaxe

Msgbox mid(txt,9,2)

Takto zapsaný řádek nám vypíše pomocí msgboxu prostřední část našeho textu tedy „je“ funkce tedy vrací námi zadaný interval znaku pomoci počáteční pozice a počtu znaků.

Ucase

tato funkce převádí zadaný textový řetězec na velká písmena, vyžaduje pouze jeden parametr a to řetězec, který chceme převést.

Ukázka syntaxe

Ucase(„ahoj“)

Toto vrátí  „AHOJ“.

Lcase

je pravý opak Ucase znamená to tedy, že převede textový řetězec na malé znaky.

vbCrlF

Nejde o funkci spíš o jakousi konstantu, která nám v kódu nahrazuje funkci enter. Jedná se tedy o zalomení řádku. Používá se například při výpisu v Msgboxu pro zpřehlednění informace. Nebo v komentáři u inputboxu. Ukážeme si použití.

Ukázka syntaxe

Msgbox(„Textový řetězec  1“ & vbcrlf & „Textový řetězec 2“ & vbcrlf & „Textový retězec 3“)
Inputbox(„Textový řetězec  1“ & vbcrlf & „Textový řetězec 2“)

U inputboxu se nám řádky zalamují na místě pro popis, je možné tedy přehledně stylovat zprávy pro uživatele jaká data má zadávat.

Příklad 1. Zde si pouze ukážeme vše co jsme si výše popsali.

Sub priklad1()

txt = "abeceda je věda"

MsgBox ("délka je (funkce len) " & vbCrLf & Len(txt))
MsgBox ("hledaný řetězec je na pozici (funkce Instr) " & vbCrLf & InStr(1, txt, "j"))
MsgBox ("funkce left " & vbCrLf & Left(txt, 4))
MsgBox ("funkce right " & vbCrLf & Right(txt, 7))
MsgBox ("funkce mid " & vbCrLf & Mid(txt, 9, 2))
MsgBox ("Vše na velké (funkce Ucase) " & vbCrLf & UCase(txt))

End Sub 

Příklad 2. Nyní si ukažme trošku těžší avšak z mého pohledu velmi praktický příklad.

Uživatel zadá textový řetězec a následně bude dotázán na hledaný znak. Program vypíše, kolikrát se znak v řetězci objevuje a na jakých pozicích.

Sub priklad1b()
    Dim Text As String
    Dim hledany As String
    Dim kde As String
    Dim pozice As Integer
    Dim Cetnost As Integer
    Dim pocatek As Integer
    
    Text = InputBox("zadej text")
    hledany = InputBox("zadej hledany text")
    
    pocatek = 1
    Do
        pozice = InStr(pocatek, Text, hledany)
        If pozice > 0 Then
            Cetnost = Cetnost + 1
            kde = kde + Str(pozice) + ","
            pocatek = pozice + 1
        End If
    Loop Until pozice = 0
    
    MsgBox ("cetnost:" + Str(Cetnost) + ";  " + "pozice:" + kde)


End Sub

Popis kódu již snad není nutný. Hlavní funkcí pro tento příklad je InStr. Pokud by však někomu dělalo potíže porozumět, doporučuji pustit si program debugem a projít si jednotlivé kroky a podívat se co se kam načítá a co se s kódem děje.

Závěr

To bude pro dnešek vše. Příště se podíváme na skládání textových funkcí a zadáme si nějaké komplexnější příklady na procvičení těchto funkci. Příklady budou podobného typu dnešního 2. příkladu budou tedy i trochu prakticky využitelné 😉 máte se tedy na co těšit.

VBA – 5# Lekce – Debug proces

Ještě než se pustíme do slibovaného příkazu „Select Case“ chtěl bych Vám ukázat tzv. Debug v MS Excel. Je to nástroj, který prochází krok po kroku námi napsaný kód. Je to dobré, pokud máme delší kód a někde máme chybu. Nebo také k lepšímu pochopení chodu programu.

Debug

Tak a teď jak na to. Nejdříve si spustíme námi napsaný prográmek třeba z minulé lekce s podmínkami IF. Jak jsme již zvyklí, přepneme se do vývojového prostředí. Debug pustíme tlačítkem F8 nebo také v záložce Debug -> položka Step Into. Aby vše fungovalo, musíme mít kurzor nakliknutý v jakékoliv části námi napsaného programu. Postupným mačkáním F8 debug prochází jednotlivé řádky našeho kódu aktuálně „projížděný“ řádek je podbarven žlutě. Pokud potřebujeme vědět, jaké data se nám aktuálně načetly do proměnné, stačí najet kurzorem na danou proměnnou a zobrazí se nám, co obsahuje. Toto platí pro všechny proměnné v kódu ne jenom na tu podbarvenou.

Závěr

S tímto nástrojem jsem Vás chtěl seznámit zejména kvůli pochopení chodu programu. Aby jste viděli, co se kam kdy načítá a měli tak větší kontakt s napsaným kódem a uměli si vše líp představit. Závěrem si dáme úkol projít všechny námi doposud napsané programy tímto postupem a znovu se zamyslet jak program funguje zejména pak programy z minulé lekce kde jsme se poprvé setkali s IF.

#9 Práce s textem

Právě dnes Vám přinášíme další díl našeho kurzu programování v jazyce C. V této lekci se budeme zabývat řetězci, zejména používání vestavěných funkcí pro práci s textem, kterých není málo a proto si ukážeme jen ty nejpoužívanější nebo spíše nejužitečnější pro základní práci s řetězci.

Poprvé jsme se o řetězcích zmínili v 6. lekci, kde jsme si ukázali jejich deklaraci, vstup do programu a následné vypsání. Nyní si informace o řetězcích trochu rozšíříme.

Charakteristika řetězců

Jak jsme si již definovali v předešlé lekci (6. lekce), že řetězec je posloupnost znaků. V jazyce C bývají zapsané jako pole znaků (charů). Každý řetězec je ukončen tzv. Binární nulou. Právě díky ukončovací nule si nemusíme pamatovat velikost pole. Pole znaků procházíme pouze do výskytu ukončovací nuly. Je možné nulu posouvat na nižší úroveň v poli, čímž se řetězec zkracuje. Znaky za ukončovací nulou nejsou zpravidla dostupná, ale při pokusu o jejich vypsání se zobrazí jakési „smetí“ z paměti.

Deklarace řetězce

char string[10]; //9 znaku + ukoncovaci nula

Pokud při deklaraci rovnou přiřadíme i nějaký řetězec, velikost pole se nastaví podle počtu znaků + ukončovací nula.

char string[] = "text"; //velikost pole = 5

Inicializace řetězce

Rozdíl v inicializaci pole a řetězce:

char str1[]="abc"; //inicializace pomoci retezcove konstanty
char str2[]={'a','b','c'}; //inicializace pole znak po znaku

Druhý zápis nevloží nakonec pole ukončovací nulu. Pro správnost musíme přidat i nulu jako 4. prvek pole.

char str2[]={'a','b','c', 0};

Pokud použijeme funkci scanf pro načtení řetězce tak syntaxe vypadá následovně:

scanf("%s", string);

Víme, že u funkce scanf se k proměnné přidává operátor reference, aby fungovala správně, jelikož proměnná typu řetězec obsahuje adresu tak se tento operátor nepřidává.

Operace s řetězci

char string[] = “Lorem ipsum”;

Vypsání určitého znaku v řetězci lze bud pomocí operátoru hranaté závorky, kde se vypíše daný prvek v poli, nebo pomocí ukazatelové aritmetiky nastavíme ukazatel na konkrétní adresu a pomocí operátoru dereference vypíšeme obsah paměti na této adrese.

printf("%c\n", string[6]);
printf("%c\n", *(string+6));

Můžeme část řetězce vložit do nového, opět za pomoci ukazatele.

char* string2 = string + 6; //string2 = "ipsum"

Můžeme řetězec zkrátit vložením ukončovací nuly. Zapsáni nuly je možné dvěma způsoby, je jedno který zvolíte.

string[5] = 0;
string[5] = '\0';

Pole řetězců

Je to pole kde typ jednotlivého prvku pole je ukazatel na řetězec (char*). Nejčastější použití takového pole je pro řadu konstantních řetězců.

char* OnlineKurzy[] = {"Lekce VBA","Lekce Pascalu","Kurz C","Webdesign"};

Funkce pro práci s řetězci

Nejprve si ukážeme pár důležitých funkcí, které se nacházejí v knihovně string.h

Funkce strlen

Je to velice používaná funkce, která vrací počet znaků v řetězci. Na příkladu vidíme rozdíl mezi sizeof a strlen. V příkladu je i test ukončovací nuly, zda se opravdu v řetězci nachází.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char string[] = "Lorem ipsum";
    printf("%s\n", string);
    printf("sizeof: %d\nstrlen: %d\n",sizeof(string),strlen(string));
    string[5] = '\0'; //vlozime ukoncovaci nulu doprostred retezce
    printf("%s\n", string);
    printf("sizeof: %d\nstrlen: %d\n\n",sizeof(string),strlen(string));

    printf("vypisuju ukoncovaci nulu jako znak:%c(vlozi mezeru)\n", string[11]);
    printf("vypisuju ukoncovaci nulu jako cislo:%d(vlozi cislo)\n", string[11]);

    return 0;
}

Pokud chceme nulu vypsat samostatně jako znak tak se na výpisu objeví mezera, při výpisu celého řetězce se tato mezera neobjeví, jelikož se vypisují pouze znaky před ukončovací nulou.

U funkce strlen opravdu vidíme, že řetězec má délku 11, ale funkce sizeof nám vrací číslo o 1 větší a to proto, že funkce ukazuje kolik je potřeba bytů na uchování tohoto řetězce v paměti. Víme, že na uložení jednoho znaku potřebujeme právě 1 byte a ten 12. byte navíc je právě pro ukončovací nulu.

Funkce strcpy

Slouží k překopírování jednoho řetězce do druhého.

strcpy(retezec1,retezec2);

Dle znázornění se zkopíruje retezec2 do retezce1. Důležité pravidlo pro použití této funkce je, že retezec1 musí být dostatečně velký, aby byl schopen uložit do sebe retezec2.

Funkce strcat

Tato funkce umožňuje spojit dva řetězce v jeden.

char str[256] = "Lorem";
printf("%s\n",strcat(str,"Ipsum"));

Výsledek bude vypadat: LoremIpsum.

Pravidlo pro tuto funkci je, že opět první řetězec musí mít dostatečnou velikost a to: (délka prvního řetězce) + (délka druhého řetězce) + 1 (ukončovací nula)

Funkce strcmp

Pro porovnání dvou řetězců se používá tato funkce.

strcmp(retezec1,retezec2);

Funkce vrací celočíselnou hodnotu:

  • hodnota 0 – vrací, jestliže jsou oba řetězce shodné
  • hodnota >0 – vrací, pokud první řetězec je větší než druhý
  • hodnota <0 – vrací, pokud první řetězec je menší než druhý

Výsledky jsou vyhodnoceny na základě uspořádání znaků v ASCII tabulce. Pokud tedy použijeme toto porovnání:

strcmp("A","a");

Hodnota velkých písmen je v ASCII tabulce před malými písmeny, tudíž funkce vyhodnotí výsledek na záporný.

Funkce strchr

Jedná se o vyhledávací funkci, která zjišťuje, zda řetězec obsahuje hledaný znak.

strchr(retezec,znak);

Pokud se hledaný znak v řetězci nachází potom funkce vrací hodnotu v podobě ukazatele na prvně nalezený znak, v opačném případě vrací hodnotu NULL.

Funkce strstr

Obdobná funkce jako předchozí, akorát s tím rozdílem, že funkce vyhledává, zda se v prvních řetězci nachází řetězec druhý. Pokud se takový řetězec najde, funkce vrací ukazatel na první výskyt řetězce.

Znakové funkce

V následující tabulce si ukážeme několik funkcí, které zjišťují charakteristiku znaku, všechny tyto funkce se nacházejí v knihovně ctype.h. Všechny funkce mají jeden parametr a to znak (char). Návratová hodnota pro všechny funkce je stejná, mohou nastat pouze 2 případy:

  • Funkce vrátí číslo různé od nuly pro PRAVDU
  • Funkce vrátí číslo 0 pro NEPRAVDU
Funkce Popis Znaky 1
isalnum(char) Je znak písmeno nebo číslo? A – Z, a – z, 0 – 9
isalpha(char) Je znak písmeno? A – Z, a – z
isblank(char) Je znak prádný? tabulátor (‚\t‘), mezera (‚ ‚)
iscntrl(char) Je znak řídící? znaky s ASCII hodnotu < 32 a znak s hodnoutou 127
isdigit(char) Je znak číslo? 0 – 9
isgraph(char) Má znak grafické znázornění? 0 – 9, A – Z, a – z, všechny speciální znaky
islower(char) Je znak malé písmeno? a – z
isprint(char) Je znak tisknutelný? mezera, 0 – 9, A – Z, a – z, všechny speciální znaky
ispunct(char) Je znak speciální? !“#$%&'()*+,-./:;<=>?@[\]^_`{|}~
isspace(char) Je znak „bílý“? tabulátor (‚\t‘), mezera (‚ ‚), nový řádek (‚\n‘), návrat vozíku (‚\r‘), vertikální tabulátor (‚\v‘), konec stránky (‚\f‘)
isupper(char) Je znak velké písmeno? A – Z
isxdigit(char) Je znak hexadecimalní číslo? 0 – 9, A – F, a – f

1) Tato položka zobrazuje znaky, u kterých daná funkce vyhodnotí znak na pravdivý

V knihovně ctype.h se nacházejí jěště 2 funkce, které převádějí znak buď na velké písmeno nebo naopak na malé. Ještě jednou zdůrazňuji, že převádejí znak nikoliv celé slovo (řetězec), pokud bychom chtěli použít jednu z těchto funkcí na celém řetězci, jednoduše použijeme cyklus, který projde řetězec znak po znaku a upraví jej podle potřeby.

Funkce Popis
tolower(char) převede velké písmeno na malé
toupper(char) převede malé písmeno na velké

 

K dnešní lekci to bude vše, doufám že jste se zase něco dozvěděli, můžete i články sdílet na sociálních sítích a podobně. V následujícím článku se zaměříme na soubory.

#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.