Posted in: Základy PowerShellu

Hodiny do PowerShellu

Dnes je to jen malý kousek kódu, který se ovšem může hodit. Na liště OS máme běžně hodiny, ale někdy se může stát, že potřebujeme promítnout někam aktuální čas, ne z nějakého jiného důvodu chceme v konzoli vidět běžící čas. Nyní přidám jednoduché jádro, digitální hodiny. Jednoduchý kód využívající nekonečného cyklu while:

while($true)
{
    cls #vyčištění konzole
    $cas = Get-Date | select Hour, Minute, Second #uložení času do proměnné
    Write-Host $cas.Hour ":" $cas.Minute ":" $cas.Second #výpis času v obvyklém formátu
    Start-Sleep -Seconds 1 #uspání procesu na 1 sekundu
}

Ručičkové hodiny do konzole

Vykreslení ručičkových hodin s pomocí grafických knihoven .NET už na internetu a jde vytvořit v libovolném jazyce s využitím trochy goniometrie. Osobně jsem chtěl simulovat ručičkové hodiny přímo v konzole pomocí vykreslování znaků. Hodiny vykreslují polohu konců ručiček, které se pohybují spíše po nějakém kosém čtverci, nežli po kruhu, protože k vykreslení dochází vypsáním pole 30 x 30 znaků. Stejně jako digitálky výše, čtou čas z operačního systému, ze kterého následně vypočítají x a y souřadnici konce ručičky každé ručičky. Problémem je relativně pomalé překreslování příkazové řádky, takže běh nevypadá úplně hezky, ale jdou a přečíst se nechají 😉

  • kolečko je hodinová ručička
  • + je minutová ručička
  • * je sekundová ručička
function get-sekunda{
    param (
        $s
    )
    #výpočet polohy sekund
    if($s -le 15)
    {
        $y = $s + 15
        $x = $s
        $plocha[$x, $y] = '*'
    }
    elseif(($s -gt 15) -and ($s -le 30))
    {
        $y = 30 - ($s - 15)
        $x = $s
        $plocha[$x, $y] = '*'
    }
    elseif(($s -gt 30) -and ($s -le 45))
    {
        $y = 15 - ($s - 30)
        $x = 30 - ($s - 30)
        $plocha[$x, $y] = '*'
    }
    elseif(($s -gt 45) -and ($s -le 60))
    {
        $y = $s - 45
        $x = 30 - ($s - 30)
        $plocha[$x, $y] = '*'
    }
}

function get-minuta{
    param (
        $m
    )
    #výpočet polohy minut
    if($m -le 15)
    {
        $y = $m + 15
        $x = $m
        $plocha[$x, $y] = '+'
    }
    elseif(($m -gt 15) -and ($m -le 30))
    {
        $y = 30 - ($m - 15)
        $x = $m
        $plocha[$x, $y] = '+'
    }
    elseif(($m -gt 30) -and ($m -le 45))
    {
        $y = 15 - ($m - 30)
        $x = 30 - ($m - 30)
        $plocha[$x, $y] = '+'
    }
    elseif(($m -gt 45) -and ($m -le 60))
    {
        $y = $m - 45
        $x = 30 - ($m - 30)
        $plocha[$x, $y] = '+'
    }
}

function get-hodina{
    param (
        $h
    )
    #převedení na 12 hodin režim
    $h = $h % 12
    #výpočet polohy hodin
    switch($h)
    {
        0 {$plocha[0, 15] = 'o'}
        1 {$plocha[5, 20] = 'o'}
        2 {$plocha[10, 25] = 'o'}
        3 {$plocha[15, 30] = 'o'}
        4 {$plocha[20, 25] = 'o'}
        5 {$plocha[25, 20] = 'o'}
        6 {$plocha[30, 15] = 'o'}
        7 {$plocha[25, 10] = 'o'}
        8 {$plocha[20, 5] = 'o'}
        9 {$plocha[15, 0] = 'o'}
        10 {$plocha[10, 5] = 'o'}
        11 {$plocha[5, 10] = 'o'}
        12 {$plocha[0, 15] = 'o'}
    }
}

$plocha = New-Object 'object[,]' 31,31

while($true)
{
    cls #vyčištění konzole
    $cas = Get-Date | select Hour, Minute, Second #uložení času do proměnné
    #Write-Host $cas.Hour ":" $cas.Minute ":" $cas.Second #výpis času v obvyklém formátu
    #inicialoizace plochy
    for($i = 0; $i -le 30; $i++)
    {
        for($j = 0; $j -le 30; $j++)
        {
            $plocha[$i,$j] = ' ' #uložení mezery do pole plochy
        }
    }
    #nastavení ciferníku
    $plocha[0,15] = '12'
    $plocha[15,30] = '3'
    $plocha[30,15] = '6'
    $plocha[15,0] = '9'
    $plocha[15,15] = '*'
    #výpočet polohy konců ručiček
    get-hodina -h ($cas.Hour) #ručička zobrazená kolečkem
    get-minuta -m $cas.Minute #ručička zobrazení plusem
    get-sekunda -s $cas.Second #ručička zobrazená hvězdičkou
    #vykreslení plochy
    for($i = 0; $i -le 30; $i++)
    {
        for($j = 0; $j -le 30; $j++)
        {
            Write-Host $plocha[$i,$j] -NoNewline
        }
        Write-Host ""
    }
    
    Start-Sleep -Seconds 1 #uspání procesu na 1 sekundu
}
Posted in: Vývoj počítačů

Funkční automatické testování

Proces funkčního testování

  • Automatizované testování je náročné na přípravu a údržbu
  • Automatizace má smysl tam, kde již nemění GUI rozraní
  • Automatizace se často využívá při regresních testech, poslední iterace SIT
  • Před nasazením automatizace je třeba analyzovat účelnost

Funkční testování

  • Má za cil ověřit 3 základní aspekty: správnou funkčnost, kvalitu, splnění BU požadavků
  • Ověření funkcionality a vlastností aplikace: ověření z pohledu byznys work float a z pohledu ověření výstupů z aplikace na základě vstupních podmínek
  • Ověření kvality aplikace: ověřujeme splnění podmínek na aplikaci z pohledu byznys uživatelů tak, aby po nasazení vykazovala minimum chyb a výpadků
  • Ne všechny nalezené chyby jsou chyby aplikace, můžou být způsobeny nehlášeným restartem serveru, výpadkem sítě, chybou v provádění testu, chybou v testovacích datech
  • Provádí se v odděleném prostředí od produkčního a provádí se ve více iteracích
  • Regresní testy jsou většinou směřovány do poslední iterace

Funkcionalita a vlastnosti

  • Je nutná definice rozsahu testů a způsobu ověření jejich správné funkčnosti
  • Není možné testovat vše

Manuální testování

Může být ovlivněno: časové plánování a neplnění termínů u aktivit předchozího testování (dopad na komplexnost testů); regresní tety navyšují časovou náročnost…

  • Pro urychlení exekuce a snížení nákladů se upřednostňují automatizované testy
  • Automatizace umožňuje opakovatelnost chyb a spouštění jednoho scénáře na více platformách
  • Automatizace umožňuje zvýšit počet testovaných případů => zvýšení kvality APP
  • Automatizované testy lze spouštět v noci => prostor pro dotestování chyb

Automatizované testování

  • Eliminuje chybu testera
  • Skript je tvořen zaznamenáním činnosti uživatele v aplikaci pomocí testovacího nástroje
  • Změna GUI je fatální změnou a skript musí být znovu vytvořen a odladěn
  • Při změně technologie je nutné zkontrolovat podporu testovacího nástroje
  • Nutno počítat s vyšší časovou náročností přípravy
  • Náročnost přípravy je kompenzována rychlostí tesů
  • Tester musí mít vyšší odbornost

Přínosy

  • Provádění regresního testování
  • Možnost otestovat větší množinu funkčností
  • Možnost kontroly většího množství dat
  • Automatický zápis protokolu

Analýza vhodnosti nasazení automatizace

  • Je třeba vycházet z provozovaného portfolia aplikací a jeho tributů: technologie, frekvence a typ změn nad jednotlivými aplikacemi
  • Automatizace vyžaduje podrobný popis testu
  • Analýzou se získá podmnožina aplikací, která připadá v úvahu jako automatizovatelná
  • Nad vybranou množinou se provede analýza vhodnosti automatizace
  • Volba vhodného nástroje (cena, kompatibilita, komfort tvorby skriptu)
  • Provedení technologického testu na dostatečném vzorku objektů z vybraných aplikací
  • Nasazování probíhá od nejvhodnější a po získání zkušeností se přibírají další aplikace
  • Je dobré ověřit vhodnost nově generovaných objektů k automatizovaném testování, jinak hrozí nutnost přehrání skriptů s každým nový buildem
  • Je třeba zahrnout automatizaci do metodiky
  • Je třeba mít zpracovaný byznys case, aby byly jasné přínosy

Opakování testů

  • Více platforem
  • Více lokálních nastavení
  • Více verzí
  • Více datových sad
  • Více iterací v releasu
  • Při chování uživatele závislém na jeho roli
  • Realizace regresních testů

Časově náročné operace

  • Opakování údajů
  • Kontrola pravopisu
  • Kontrola mrtvých odkazů
  • Zachycení výsledků
  • Ověření výpočtu

Bod ověření

  • Je možné kontrolovat textová pole, obrázek, nebo celou tabulku či binární srovnání
  • Možností kontroly je i přímí přístup dotazem do databáze a porovnání výsledků s hodnotami z databáze
  • Je nutná specifikace očekávané hodnoty

Akce a parametrizace

  • Skripty jsou často děleny do menších částí – akcí
  • Akce se podobají funkcím ve standartním programování
  • Pokud chceme skript sestavit z akcí je nutné, aby byla mezi koncem jedné a začátkem druhé akce návaznost
  • Parametry jsou lokální pro konkrétní akci a globální pro celý test
  • Je nedílnou součástí tvorby skriptu
  • Parametrizují se jen hodnoty, které na ni mají požadavek, nebo pokud ji vyžaduje samotný běh skriptu
  • Pokud je vstupní hodnotou parametr, tak se s každou iterací mění a je vhodné jej parametrizovat

Byznys proces testing

  • Je odvislý od akcí
  • Jednotlivé byznys procesy jsou rozděleny do akcí zvaných komponenta
  • Komponenty jsou analytikem sestaveny do testů
  • Testy spouští a vyhodnocuje tester
  • Je vhodné pro skládání obrazovek dílčích funkčností a jejich ověření před dokončením funkčního modulu pro black box testy
  • Komponenta je uzavřenou entitou, která neobsahuje žádné akce ani volání jiné komponenty
  • Parametry komponenty jsou lokální, nelze užít globální proměnné
  • Jednotlivé komponenty neobsahují ani vlastní repozitory objektů, existuje jedna sdílená pro všechny komponenty
  • Všechny komponenty jsou externí a uložené v projektu Quality Center
  • Jméno komponenty je též uloženo v QC a z QTP není měnitelné
  • Datová tabulka komponenty má pouze jeden lokální list
  • Pro vstupy a výstupy se užívá jen jeden řádek datové tabulky, data dalších iterací jsou definována v QC
  • Vždy je využívána pouze jedna datová tabulka uložená spolu s komponentou
  • Komponenta má některé vlastní nastavení a možnosti

Stálé problémy automatizace

  • Přehnaná očekávání zákazníka
  • Výsledek ještě snížen nevhodným výběrem nástroje
  • Nevhodný výběr test cases
  • Údržba skriptů i malá změna vede k jeho nefunkčnosti
  • Problém s QA inženýry, málo jich umí i programovat => vyšší nákladnost
Posted in: Různé, Vývoj počítačů

C++ pro začátečníky videotutoriál

Tutoriál, na který odkazuji umístila na svůj Youtube kanál Saldina Nurak. Výhodou je, že její angličtina je velmi dobře srozumitelná i začátečníkům a lidem, kterým jazyky nejdou. Určitou výhodou může být ona sama, jde o velmi pohlednou slečnu, která vykládá úplné začátky skutečně sruzumitelně.
A ruku na srdce, kdo by se u výkladu krom kódu nechtěl podívat na hezkou ženu, přeci jen tutoriál má 10 hodin, ale je přehledně třízen do kapitol, jejichž seznam je v popisku.

Tento Tutoriál beru jako vhodný doplněk ke knize C++ Bez předchozích vlastností od Jeff Kenta, ze které jsem se sám učil. Velkou výhodou je, že kniha je dostupná v češtině. Online je kniha dostupná na: Jeff Kent. C++ bez předchozích znalostí – PDF Free Download (adoc.pub) a stažení: https://adoc.pub/download/jeff-kent-c-bez-pedchozich-znalosti.html

Nyní již slíbený tutoriál:

Posted in: Studijní materiály, Vývoj počítačů

Základy UML

  • UML je standart v oblasti objektově orientovaných analýz

Základní cíle

  • Poskytnutí použitelného visuálního modelovacího jazyka pro vytváření a výměn smysluplných modelů
  • Poskytnout mechanismy rozšiřitelnosti a specializace pro rozšíření základních konceptů
  • Vytvořit specifikaci nezávislou na konkrétních programovacích jazycích a procesech vývoje a analýzy
  • Poskytnout formální základ pro pochopení modelovacího jazyka
  • Podporovat rozvoj objektových nástrojů
  • Podporovat vývojové koncepty jako jsou koncepty spolupráce, pracovní rámce a vzory
  • Zahrnout best practice
  • Vznikají metodiky, které sjednocují výhodné notace a postupy jednotlivých metod
  • Současná verze je 2.3
  • Verze 2.3 je visuální modelovací jazyk umožňující zachytit a opsat strukturální a dynamické aspekty SW systému

Definice

  • Je standart konsorcia OMG pro záznam, vizualizaci a dokumentaci artefaktů systémů s převážně SW charakteristikou
  • Definuje 13 základních druhů diagramů
  • Smyslem je vytvořit obecně srozumitelný pohled
  • UML není metodika

Pokytuje

  • Notaci
  • Syntaxi, jako standart pro zobrazení a popis modelů
  • Pravidla pro pojmenovávání
  • Pravidla pro rozsah platnosti
  • Pravidla pro rozsah viditelnosti
  • Pravidla pro omezení
  • Pravidla pro provedení modelu
  • Různé specifikace
  • Rozšiřitelnost jako jsou stereotypy, dodané hodnoty
  • Obsahuje mechanismy pro jeho další rozšíření dle konkrétních potřeb projektu
  • Nejčastěji je spojován s modelováním OO SW, ale má širší uplatnění

Úrovně využívání

  • Zavádí a standardizuje přehlednou grafickou notaci
  • Zle užít přímo (zakreslení obrázku návrhu), nebo zpětně (zakreslení již existujícího kódu)
  • Slouží jako dokumentační prostředek k dokumentaci systému nebo jeho části
  • Užíváme jako programovací jazyk, ze kterého ze kterého se skutečná implementace (její kostra) generuje

Součásti

Notace (syntaxe)

  • Při analýze požadavků se často jako nástroj komunikace mezi zadavatelem a řešitelem využívá modelování
  • Vznikají různé modely systému, které mohou být na této úrovni ověřovány, testovány a upravovány
  • Po dosažení schody mezi analytikem a zadavatelem je cílový model implementován do konkrétního jazyka a přeložen
  • Notace definuje, jak se zapisují základní pohledy na modelovaný systém

Metamodel UML(sémantika)

Jazyk OCL pro popis omezení v modelech

Specifikace převodu do výměnných formátů (CORBA, IDL, XML)

Diagramy

  • Zachycují různé pohledy (aspekty) modelovaného systému, který nemusí být vyjádřen jen jedním UML diagramem
  • Pomocí balíčků je možné diagramy slučovat do jednoho organizovaného celku => jeden pohled na systém může vyjadřovat více diagramů
  • Statickou strukturu systému vyjadřují diagramy tříd (znázorňují datový model systému od koncepční úrovně až po implementaci), spolupráce, komponent a nasazení
  • Funkční stránku popisují model jednání (dokumentují možné případy užití systému – události na které systém musí reagovat), diagramy aktivit, scénáře událostí a diagramy spolupráce
  • Dynamickou stránku popisují stavové diagramy, scénáře událostí, diagramy spolupráce(zachycují spolupráci a komunikaci objektů) a diagramy aktivit
  • Scénář činnosti popisuje scénář průběhu určité činnosti v systému
  • Stavové diagramy – popisují dynamické chování objektu nebo systému, možné stavy a přechody mezi nimi
  • Diagramy aktivit – popisují průběh aktivit procesu či činnosti
  • Diagramy komponent – popisují rozdělení výsledného systému na funkční celky a definují náplň jednotlivých komponent
  • Diagramy nasazení – popisují umístění komponent na výpočetní uzly informačního systému
  • Hierarchie diagramů UML 2.0:
  • Diagram objektů: je snímkem objektů a jejich vztahů v systému v určitém časovém okamžiku
  • Diagramy komunikace – dříve diagram spolupráce, zachycují komunikaci a spolupráci objektů
  • Diagramy vnitřní struktury – umožňují znázornit interní strukturu komplexního prvku (třídy, komponentu) a zobrazit spolupráci tohoto prvku neboli klasifikátoru s ostatními prvky systému
  • Diagram přehledu interakcí – srozumitelně a přehledně znázorňuje větvení i souběžnost a zachycuje procesy protínající více případů užití
  • Diagram časování – patří do skupiny diagramů interakcí a umožňuje modelování systémů pracujících v reálném čase
  • Elementy:
  • Vztahy mezi elementy:

Diagramy tříd

  • Zobrazují statickou strukturu
  • Rozlišuje několik druhů tříd, abstraktní, parametrizované atd.
  • Stavy pojící třídy: asociace, agregace, kompozice, specializace, generalizace

Diagram objektů

  • Zobrazuje objekty jako instance tříd a jejich vztahy
  • Je instancí diagramu tříd

Diagram balíčků

  • Umožňuje získat přehled o vztazích elementů rozsáhlých systémů

Diagram případů užití

  • Je soubor případů užití, aktérů a jejich vztahů
  • Každý případ užití popisuje posloupnost událostí
  • Aktér je entita inicializující posloupnost

Diagram komponent

  • Ukazuje fyzický pohled na systém, strukturu SW komponent a závislostí mezi nimi včetně klasifikátorů, které je specifikují a artefaktů (soubory se zdrojovými nebo binárními kódy)

Diagram vnitřní struktury

  • Zobrazuje vnitřní strukturu klasifikátoru včetně jeho interakčních bodů s ostatními částmi systému
  • Ukazuje spojení částí, které společně vykonávají chování klasifikátoru
  • Umožňuje rozložit komplexní objekt na jednotlivé části a zobrazit jeho strukturu

Diagram nasazení

  • Zobrazuje strukturu uzlů, kde jsou komponenty rozmístěny
  • Definuje konfiguraci spustitelných položek a SW komponent, procesů a jimi spouštěných komponent
  • Instance SW komponent reprezentují běžící projevy jednotek SW kódu
  • Komponenty, které neexistují jako běžící entity se na diagramu nezobrazí

Diagram aktivit

  • Dříve nazýván vývojový diagram

Stavový diagram

  • Slouží k modelování dynamického chování a změn v systému
  • Prezentují stavy objektů, přechody mezi stavy a ukazují počáteční a koncový bod změn
  • Zachycuje stav jediného objektu

Sekvenční diagram

  • Popisují spolupráci skupiny objektů za účelem specifického chování
  • Patří mezi nejčastěji užívané diagramy interakcí
  • Popisuje chování objektu v rámci jednoho scénáře

Diagram komunikace

  • Zobrazuje účastníky interakce a datová spojení mezi nimi
  • Zobrazuje jiným způsobem podobnou informaci jako sekvenční diagram
  • Dovoluje volné vkládání účastníků, jejich propojování čarami spojení a pomocí číslování zobrazovat sekvence správ
  • Je vhodnější při zobrazení spojení

Diagram přehledu interakcí

  • Je variantou diagramu aktivit, které dávají přehled o toku řízení v rámci systému
  • Základem jsou uzly výskytu výskytů interakcí spojené toky řízení
  • Každý prvek diagramu může být reprezentován jiným interakčním diagramem
  • Užívá symboly diagramu aktivit
  • Uzly jsou reprezentovány interakcemi a výskytem interakcí

Diagram časování

  • Je jeden z diagramů interakce, kde se zaměřujeme na změny omezení uvnitř a mezi čarami života podél lineární časové osy
  • Diagramy zachycují změny stavů nebo podmínek objektu nebo role ve vztahu k času
  • Nejčastěji zachycují změny stavu jako reakce na vnější události

OCL

  • Je čistě funkcionální jazyk
  • Neexistuje globální paměť
  • Je silně typový jazyk (každý výraz má definován typ)
  • Primitivní typy: Integer, Boolean, String, Real, Unlimitedinteger
  • Kolekce: Set, Bag, Collection, Sequence,
Posted in: Studijní materiály, Vývoj počítačů

Úvodní vhled do jazyka C

Zpracování programu

Editor Slouží pro zápis zdrojového kódu programu a ukládá ho s příponou .c. Preprocesor Předzpracuje zdrojový kód. Vkládá hlavičkové soubory s příponou .h, vynechává komentáře, rozvíjí makra atd. Compiler Převede zdrojový kód do relativního kódu počítače tak, že adresy proměnných a funkcí nejsou známy a jsou relativně zapsány do souboru *.obj. Soubor *.lis je protokol o překladu. Linker Přidělí relativním adresám adresy absolutní, najde adresy neznámých identifikátorů a připojí všechny potřebné knihovny *.lib. Debuger Hledá chyby nastávající při běhu programu a po nalezení chyby se celé zpracování programu opakuje. První program
Pro ilustraci toho jak vypadá program v C si uvedeme jednoduchý program který vypisuje text: „Hurá, můj první program v C!!!“

//Můj první program 
#include <stdio.h> 
int main()
{ 
   printf("Hura, muj prvni program v C!!!");
   getch(); 
   return(0);
}

V prvním řádku s vyskytuje komentář. V jazyce C se zapisuje jednořádkový komentář ve tvaru //jednořádkový komentář. Víceřádkový se zapisuje /* viceřádkový komentář */. Dále se v kódu vyskytuje direktiva (příkaz preprocesoru) #include , která zajišťuje připojení knihovny funkcí. V tomto případe stdio.h pro standardní formátovaný vsup a výstup. Hlavní program je zapsán do funkce main(), kterou musí obsahovat každý program. Začátek a konec programu zapisujeme pomocí tzv. bloku { … }. Definice funkcí (i hlavní funkce main()) většinou obsahují nepovinný příkaz return. V těle programu je funkce pro tisk na standardní výstup printf() a po ní funkce getch(), která je zde jen proto, aby se okno programu nezavřelo hned po spuštění. Místo této funkce lze použít elegentnější řešení s pomocí system(„pause“). V tomto programu se jednalo o pouhé nastínění toho, jak má program v C vypadat. V dalších lekcích se dozvíte vše podrobněji. Klíčová slova Je to množina slov, kterým překladač jazyka C rozumí a má je ve své slovní zásobě. Proto je nelze použít jako identifikátor či název funkce.

  • auto
  • break case char
  • const
  • double int else
  • long
  • extern return float
  • short
  • continue for default do
  • goto if
  • struct switch
  • enum register typedef union
  • unsigned signed void
  • sizeof volatile static while

Proměnné

Proměnné jsou paměťová místa přístupná prostřednictvím identifikátoru. Hodnotu proměnných můžeme během výpočtu měnit. Pro deklaraci proměnné používejte tento obecný formát: typ identifikátor; Pro deklaraci více proměnných stejného datového typu se používá tento zápis: typ identifikátor_1, identifikátor_2, identifikátor_3; V deklaraci může být proměnná současně inicializována, tj. můžeme jí přiřadit počáteční hodnotu: typ identifikátor=hodnota; Proměnné deklarované mimo všechny funkce jsou globální, můžeme je použít kdekoli v programu a jsou implicitně nulové. Proměnné deklarované ve funkcích či v bloku se nazývají lokální proměnné, můžeme je použít jen v dané funkci či bloku a jsou implicitně nenulové.

Datové typy

Datové typy určují rozsah hodnot, velikost alokované paměti a množinu přípustných operací. Dělíme je na: Jednoduché

bez hodnoty void
celočíselné: short (16b), int (16b|32b dle tzpu CPU), long (32b), char (8b)
výčtový typ: enum (8b|16b|32b)
reálné: float (32b), double long (64b), double (80b)

Strukturované

struktura: struct
unie: union
soubor: FILE
pole a řetězec nemají klíčové slovo, jsou složeny ze základních datových typů. Velikost proměnné a rozsah jejich hodnot závisí na implementaci překladače v operačním systému. Typy float, double a long double se používají pro reálná čísla. Typ int a z něj odvozené typy short int a long int pracují s celými čísly. Poněkud překvapivě patří k celočíselným typům i char. Je sice určen pro uložení jednoho znaku, ten je však v jazyce c reprezentován jako číslo. Všechny celočíselné typy mohou být prefixem unsigned deklarovány jen pro čísla bez znaménka. Implicitně jsou deklarovány jako signed. Pro zjištění velikosti daného datového typu se používá operátor sizeof. Operandem je buď datový objekt (např. proměnná nebo pole) sizeof identifikátor; nebo název typu uzavřený do závorek. sizeof (datový typ); Výsledek je v bajtech.

Konstanty

Konstanta je datový prvek jehož hodnota je neměnná. Překladač přiřadí konstantě typ odpovídající hodnotě. Uvozuje se klíčovým slovem const. Dělíme je na:
Celočíselné

druhzápis
desítkovédesítkové_číslo
osmičkové0osmičkové_číslo
šestnáctkové0xšestnáctkové_číslo

C umožňuje určit typ číselných konstant pomocí sufixu. Celá čísla můžeme zapsat jako long pomocí sufixu ‘l’ nebo ‘L’, nebo bez znaménka čili unsigned pomocí ‘u’ nebo ‘U’.

Reální

druhzápis
Desetinný zápiscelá_část.desetiná_část
semilogaritmický zápismantisaeexponent nebo mantisaEexponent

Implicitní typ racionální konstanty je double. Pro typ float uvedeme číslem ‘f‘ nebo ‘F‘. Pokud za číslo dáme ‘l’ nebo ‘L’ stane se z čísla long double.

Znakové

zápisvýznam
‚znak‘řetězec

Znakové konstanty jsou jeden znak obklopený apostrofy. Proto abychom mohli ve znakových a také řetězcových konstantách zapisovat speciální a negrafické znaky používají se tzv. escape sekvence. Začínají lomítkem a využívají se zejména ve výstupních funkcích jako např. printf. Jejich seznam je následující:

zápisvýznam
\0prázdný znak (je na konci každého řetězce)
\apípnutí
\bnávrat o jeden znak zpět
\fnová stránka nebo obrazovka
\npřesun na začátek nového řádku
\rpřesun na začátek aktuálního řádku
\tpřesun na následující tabelační pozici
\vpřesun dolů
\\obrácené lomítko
\‘apostrof
\“uvozovky
\?otazník

Řetězcové

Zapisují se jako posloupnost znaků obklopená uvozovkama.

Operátory

Operátory určují operaci, kterou hodláme provést s operandem. Např.: a + b, ‚a‘ a ‚b‘ jsou operandy a ‚+‘ je operátor Dělení:dle počtu operandů: unární (1), binární (2), ternární (3) dle funkce operátorů: aritmetické, relační, logické, bitové, přiřazovací, ternární, inkrementace a dekrementace a ostatní Aritmetické

zápisvýznam
+, -, *sčítání, odčítání, násobení
/celočíselné dělení (když jsou oba operandy celé číslo), reálné dělení (když je alespoň jede operand reální číslo)
%dělení modulo, neboli zbytek po celočíselném dělení

Relační

zápisvýznam
<, <=, >, >=menší než, menší nebo rovno, větší než, větší nebo rovno
==rovnost
!=nerovnost

Logické

zápisvýznam
&&logický součin (AND)
||logický součet (OR)
!negace

Bitové

zápisvýznam
>>, <<bitovém posunu vpravo a vlevo
&logický součin (AND)
|logický součet (OR)
~negace
^XOR

Přiřazovací

zápisvýznam
=přiřazení
+=, -=, *=, /=zkrácený výraz pro proměnná=proměnná+číslo atd.
!negace

Inkrementace a dekrementace

zápisvýznam
++inkrementace, zkrácený zápis pro proměnná=proměnná+1
dekrementace, zkrácený zápis pro proměnná=proměnná-1

Ostatní operátory

zápisvýznam
(datový_typ)operátor přetypování
sizeofoperátor pro zjištění velikosti datového typu či datového objektu
&operátor adresy
()operátor volání funkce
[]operátor prvku pole
.výběr prvku struktury
->výběr prvku struktury zadané ukazatelem

Vstupní/výstupní funkce

Aby uživatel mohl s programem aktivně pracovat používáme vstupní a výstupní funkce. Formátovaný vstup a výstup zajišťují tyto funkce: scanf(„formátovacířetězec“, adresy); printf(„formátovacířetězec“, proměnné_či_výrazy); Protože jazyk C má malé jádro, musí většinu funkcí připojovat. K tomu abychom je připojili musíme do zdrojového kódu zapsat názvy hlavičkových souborů obsahující potřebné funkce. Zapisujeme je do hlavičky programu. V případě formátovaného vstupu/výstupu to je stdio.h. Přidáme jí takto:

#include <stdio.h>

Formátovaný výsup printf()

printf(„formátovacířetězec“, proměnnéči_výrazy); Formátovací řetězec se skládá z úseků textu, které se beze změny objeví na výstupu, a formátové specifikace (konverze) určující, v jakém tvaru se hodnoty proměnných či výrazů zobrazí. Každá formátová specifikace začíná znakem % a končí písmenem, které musí odpovídat typu vypisované hodnoty Výrazy či proměnné jsou čteny z leva doprava. Vkládáme-li do formátovacího řetězce více výrazů či proměnných, oddělíme je čárkami. Forátovaný vstup scanf() scanf(„formátovací_řetězec“, adresa); Formátovacím řetězcem je určena formátová specifikace vstupní hodnoty (pomocí % a odpovídajícího písmene). Adresa určuje paměťovou oblast, do níž bude odpovídající vstupní hodnota uložena a zapisuje se ve tvaru &identifikátor_proměnné. V praxi jde nejčastěji o adresu proměnné, nebo o ukazatel na pole znaků. Čtení ze vstupu probíhá tak, že první formátová specifikace je použita pro vstup první hodnoty, která se uloží na první adresu po stisku klávesy Enter atd. Čteme-li více hodnot oddělujeme adresy proměnných čárkami. Formátová specifikace Formátová specifikace má obecně tento tvar: %[.přesnost][modifikátor]konverze Konverze je označena jedním znakem, mezi znakem % a označením konverze mohou být umístěné další (nepovinné) parametry jako modifikátor či přesnost. Konverze pro printf() a scanf() jsou stejné.

konverze

Modifikátory

Přesnost

Zapisuje se desetinou tečkou. Přesnost je dekadické číslo, které pro konverze d, i, o, u, x, X znamená minimální počet cifer na výstupu, pro konverze f, e, E, znamená počet cifer za desetinnou tečkou, pro konverze g, G znamená počet významových cifer a pro konverzi s maximální počet znaků. Formátovaný vstup a výstup může vypadat třeba takto:

#include <stdio.h> 
int x,y; 
int main(){ 
   printf("Zadejte dve cisla: \n"); 
   scanf("%d %d", &x, &y); 
   printf("Soucet %d a %d je roven: %d\n", x, y, x+y); 
   printf("Rozdil %d a %d je roven: %d\n", x, y, x-y); 
   printf("Soucin %d a %d je roven: %d\n", x, y, x*y); 
   printf("Podil %d a %d je roven: %.2f\n", x, y, (float)x/y); 
   getch(); 
   return(0);
}

Znak ‚\n‘ je zde interpretován jako přechod na novou řádku. Kombinace %d, %f jsou konverze určené pro výstup hodnot po řadě typu int a float. Vstup a výstup znaků Pro vstup znaků je určena funkce getchar() ze standardního vstupu. Pro výstup znaků na standardní výstup je určena funkce putchar(). Používá se pro ně následující zápis: getchar(znak); putchar(znak); Pro vstup znaku je taky možno použít funkci getch(), která se nachází v hlavičkovém souboru conio.h. Rozdíl mezi getch() a getchar() je takový, že getch čeká na stisknutí klávesy Enter, kdežto getch() okamžitě reaguje na vstup. Sekvence Sekvencí nebo blokem se rozumí posloupnost příkazů ohraničená znaky { }. Mezi těmito závorkami mohou být libovolné jiné příkazy včetně dalších bloků. Používá se ve větvení, cyklech a funkcích. Na začátku sekvence je vhodné definovat lokální proměnné. Blok se chová jako jeden příkaz.

Větvení

Alternativa neboli větvení nám zajišťuje provedení příkazu za určité podmínky. Rozlišujeme 3 typy: úplná, neúplné, vícenásobná

Úplné

Obecný zápis vypadá takto: if (podmínka) příkaz_1; else příkaz_2; Za klíčovým slovem if následuje podmínka povinně uzavřená do závorek. Je-li podmínka pravdivá (nenulová), potom se provede příkaz_1, je-li nepravdivá (nulová), pak se provede příkaz_2 Alternativy můžeme do sebe navzájem vnořovat. Vnořená alternativa vypadá takto: if (podmínka) příkaz_1; else if (podmínka) příkaz_2; else příkaz_3; V následujícím programu se pomocí úplné vnořené alternativy zjisti zda je číslo kladné, záporné nebo nula.

#include <stdio.h> 
int a; 
int main(){ 
   printf("Zadej cislo: "); 
   scanf("%d",&a); 
   if (a>0) 
   {
      printf("Cislo je kladne"); 
   }else if (a<0) 
       {
         printf("Cislo je zaporne"); 
       }else 
       {
         printf("Cislo je nula");
       }
   getch(); 
   return(0);
}

Neúplné

Obecný zápis vypadá takto: if (podmínka) příkaz_1; Je shodná s úplnou alternativou s tím rozdílem, že v ní chybí příkaz else. Je-li podmínka nepravdivá (nulová) pokračuje se v programu dále. V tomto programu se pomocí neúplné alternativy zjisti zda je číslo kladné, záporné nebo nula.

#include <stdio.h> 
int a; 
int main()
{ 
   printf("Zadej cislo: "); 
   scanf("%d",&a); 
   if (a>0) 
   {
      printf("Cislo je kladne"); 
   }if (a<0) 
   {
     printf("Cislo je zaporne");
   }if (a==0) 
   {
      printf("Cislo je nula"); 
   }
   getch();
   return(0);
}

Vícenásobné

Zápis vícenásobné alternativy vypadá následovně: switch(selektor) { case hodnota_1: příkaz_1; break; case hodnota_2: příkaz_2; break; … case hodnota_n: příkaz_n; break; default: příkaz; } Vícenásobná alternativa switch neboli přepínač se vyhodnocuje tak, že se porovná selektor s celočíselnými nebo znakovými hodnotami ze seznamu a dojde-li ke shodě provede se příslušný příkaz. Příkaz break způsobí ukončení provádění příkazu switche. Za jeho absence by se provedly příkazy následujících case. Příkaz default není povinný a provede se v případě že podmínce nevyhovuje žádná hodnota za nabízených case. Pomocí vícenásobné alternativy můžeme zpracovat program takovéhoto zadání: Uživatel zadá počet mobilů, které chce zakoupit. Cena za jeden mobil je 6999Kč, při odběru dvou nebo tří mobilů je cena 5999Kč,při odběru 4,5, nebo 6 kusů je cena 4999Kč a při odběru nad 7 kusu je cena jednoho 3999Kč. Určete celkovou částku, kterou kupující zaplatí.

#include <stdio.h> 
int pocet,cena; 
int main(){ 
   printf("Zadej pocet mobilu: "); 
   scanf("%d",&pocet); 
   switch(pocet) {}{
      case 1:cena=6999; 
             break; 
      case 2:
      case 3:cena=5999; 
             break; 
      case 4:
      case 5: 
      case 6:cena=4999; 
             break; 
     default:cena=3999;
   } 
   printf("Cena za kus: %dKc\n",cena); 
   printf("Celkova cena: %dKc\n",pocet*cena); 
   getch(); 
   return(0);
}

Cykly

Cykly používáme v případě, že potřebujeme nějakou činnost provádět opakovaně. U cyklů používáme nějakou podmínku, která říká, kolikrát se daná činnost provede. Rozlišujeme dva typy cyklů: s podmínkou na začátku a s podmínkou na konci.

Cyklus s podmínkou na konci

Cyklus s podmínku na konci se zapisuje pomocí klíčových slov do a while. Jeho obecný zápis vypadá následovně: do příkaz; while(podmínka); Pracuje tak, že se provede tělo cyklu a poté se vyhodnotí podmínka, je-li pravdivá (nenulová) opakuje se tělo cyklu. Je-li podmínka nepravdivá (nulová) cyklu se ukončí. Tento cyklus se používá v případech, kdy potřebujeme tělo cyklu vykonat alespoň jednou. Příkladem cyklu s podmínkou na konci může být zjištění ciferného součtu zadaného čísla:

#include <stdio.h> 
int n, cislo; 
int main(){ 
   printf("Zadej cislo pro vyocet ciferneho souctu \n"); 
   scanf("%d",&n); 
   do {}
   {
      cislo=n%10+cislo; 
      n=n/10;
   }
   while((n%10)!=0); 
   printf("Ciferny soucet je %d",cislo); 
   getch(); 
   return(0);
}

Cyklus s podmínkou na začátku

Cyklus s podmínku na začátku se zapisuje pomocí klíčového slova while. Jeho obecný zápis vypadá následovně: while(podmínka) příkaz; Nejprve se vyhodnotí podmínka. Když je pravdivá (nenulová) je provedeno tělo cyklu. Když je nepravdivá (nulová) cyklus se ukončí Cyklus while se dá například použít pro výpočet faktoriálu zadaného čísla.

#include <stdio.h> 
int n, faktorial=1; 
int main()
{ 
   printf("Zadej cislo pro vyocet faktorialu \n"); 
   scanf("%d",&n); 
   if(n<0) 
   {
      printf("Faktorial zaporneho cisla neni mozny!"); 
   }else{
      while(n>0){
         faktorial=faktorial*n; 
         n--;
      }
   printf("Faktorial je %d",faktorial); 
   }
   getch(); 
   return(0);
}

Cyklus s pevným počtem opakováním

Cyklus s podmínku na začátku se může zapsat také pomocí klíčového slova for. Jeho obecný zápis vypadá takto: for(inicializace; podmínka; iterace) příkaz; Cyklus for pracuje tak, že se nejprve inicializuje proměnná, poté se vyhodnotí podmínka (je většinou tvořena relačními operátory) a při její pravdivosti se provede tělo cyklu. Při nepravdivosti se cyklus ukončí. Pak se provede iterace (nejčastěji inkrementace či dekrementace). Použijeme jej tehdy, známe-li předem počet opakování průchodů. V cyklu for můžeme inicializaci, podmínku a iteraci vynechat. Pak vytvoříme nekonečný cyklus ve tvaru: for(;;) příkaz; Cyklus for může mít třeba použití v programu ve kterém máme načíst celé kladné číslo a zjistit kterými čísly je celočíselně dělitelné.

#include <stdio.h> 
int i, cislo; 
int main()
{
   printf("Zadej cislo pro zjisteni delitelu \n"); 
   scanf("%d",&cislo); 
   for(i=1;i<cislo;i++) 
   {
      if(cislo%i==0) 
      {
        printf("%d ",i); 
      }
   }
   getch();
   return(0);
}

Break a continue

Tyto příkazy lze použít ve všech cyklech. Mění provádění cyklu. break Způsobí ukončení cyklu. Díky příkazu break dochází k větší efektivitě a pružnosti cyklů. Můžeme například upravit příklad uváděný u cyku for a vyjmout všechny jeho atributy.

#include <stdio.h> 
int i=1, cislo;
int main()
{
   printf("Zadej cislo pro zjisteni delitelu \n"); 
   scanf("%d",&cislo); 
   for(;;){
    if(i>cislo) break; 
    if(cislo%i==0) 
    {
       printf("%d ",i); i++;
    }
   } 
   getch(); 
   return(0);
}

continue

Ukončí aktuální průchod cyklem. Cyklus není ukončen a pokračuje se dalším průchodem cyklu. goto Způsobí nepodmíněný skok na návěští. Není příliš používaný, jelikož porušuje zásadu strukturovaného programování. Dal by se použít třeba takto: goto návěští; příkazy_které_se neprovedou návěští: příkaz;

Funkce

unkce je základní programovou jednotkou v jazyce C. Každý program obsahuje alespoň jednu funkci – main(). Obecně by se definice funkce dala zapsat takto: návratový_typ identifikátor_fce(formální parametry) { . . . return návratová_hodnota; } Definice funkce se skládá z hlavičky a těla. Pokud není určen návratový typ je implicitně int. Formální parametry jsou lokální proměnné platné jen v dané funkci. Čtou se zprava do leva a proto je nutné u každého uvést datový typ. Formální parametry se proto zapisují takto: dat_typ identifikátor_1, dat_typ identifikátor_2, … Jsou volány hodnotou, tedy neovlivňují hodnotu načtených skutečných parametrů. Pro volání adresou (odkazem), tedy pro předání hodnoty skutečným parametrům ve funkci užíváme pointery. Příkaz return ukončí funkci a předá nepovinnou návratovou hodnotu programové jednotce, která funkci vyvolala. Funkce může obsahovat libovolné množství příkazů return nebo ani jeden. Funkci můžeme definovat před funkcí main() nebo za main(). Definujeme-li funkci za main() musíme uvést deklaraci funkce v hlavičce programu, aby kompilátor při průchodu programem věděl o použití funkce. Deklarace vypadá stejně jako hlavička definice funkce se středníkem: návratový_typ identifikátor_fce(formální parametry); V programu pak funkci zavoláme takto: identifikátor_fce(skutečné parametry); Následujíc příklad ukazuje jak vytvořit funkci definovanou před main(). Funkce vrací absolutní hodnotu zadaného čísla.

#include <stdio.h>
float abs_hodnota(float x){
   if(x>0) return(x); 
   else return(-x);
} 
float cislo; 
int main()
{ 
   printf("Zadej cislo pro absolutni hodnotu\n"); 
   scanf("%f", &cislo); 
   printf("Absolutni hodnota cisla %.4f je %.4f", cislo, abs_hodnota(cislo)); 
   getch(); 
   return;
}

V dalším programu je funkce definována za main(), tudíž je v programu deklarace funkce.

#include <stdio.h> 
int nsd(int a, int b); 
int cislo1, cislo2; 
int main(){ 
   printf("Zadej dve cela kladna cisla\n"); 
   scanf("%d %d", &cislo1, &cislo2); 
   if(cislo1>0 && cislo2>0) 
   {
     printf("Nejvetsi spolecny delitel cisla %d a %d je %d", cislo1,
     cislo2, nsd(cislo1, cislo2)); 
   }else printf("Bylo zadano zaporne cislo!"); 
   getch(); 
   return;
} 
int nsd(int a, int b)
{ 
   int i, max; 
   for(i=1;i<=((a<b)?a:b);i++) 
   {
      if ((a%i==0)&&(b%i==0)) max=i; 
   }
   return(max);
}

Pokud chcete aby funkce nevracela žádnou hodnotu, čili vytvořit proceduru, stačí uvést jako návratovou hodnotu funkce datový typ void jako v následujícím příkladu

#include <stdio.h>
void oddelovac();
int main()
{
   oddelovac(); 
   printf("Cecko je fajn\n");
   oddelovac(); 
   printf("A mam ho strasne rad\n"); 
   oddelovac(); 
   getch(); 
   return;
} 
void oddelovac(){
   int i; 
   for(i=1;i<=20;i++) printf("*"); 
   printf("\n");
   return;
}

Rekurzivní funkce

Je funkce která při svém běhu volá sama sebe. Musí obsahovat podmínku která určí kdy se má vnoření zastavit.

#include <stdio.h> 
int faktorial(int n); 
int cislo; 
int main(){ 
   printf("Zadej ciso pro faktorial\n"); 
   scanf("%d", &cislo); 
   if(cislo<0) printf("Faktorial zaporneho cisla neni mozny!"); 
   else printf("Faktorial je %d", faktorial(cislo)); 
   getch(); 
   return;
} int faktorial(int n){
   if(n>1) return(n*faktorial(n-1)); 
   else return(1);
}

Preprocesor

Preprocesor jazyka C slouží k předpřipravení zdrojového kódu pro kompilátor. Jeho úkolem je odstraňování komentářů, vkládání hlavičkových souborů, rozvoj maker a provádění podmíněného překladu. Činnost preprocesoru řídíme pomocí tzv. direktiv preprocesoru. Direktiva preprocesoru není příkaz jazyka C, proto za ní neuvádíme středník. Každá direktiva je uvozena znakem ‚#‘ , který musí být uveden hned jako první znak na řádku. Tak určíme, že zbytek řádku je určen preprocesoru. Chceme li ovšem ať preprocesor zpracuje i text na druhém řádku musíme přidat na konec řádku znak ‚\‘.

Makra

Makro je text, který je v podstatě zdrojovým kódem. Jako se zdrojovým kódem se s ním však
pracuje až po zpracování preprocesoru, kdy se výskyt identifikátoru makra ve zdrojovém kódu nahradí textem makra. Pro definici makra používáme direktivu #define Máme dva typy maker: bez parametrů a s parametry

Makra bez parametrů

Používají se pro definování symbolických konstant, kdy místo konstanty používáme nějaké symbolické jméno. Ustáleným pravidlem je psát identifikátor makra bez parametru velkými písmeny. Zápis vypadá takto: #define identifikátor_makra text_makra Volání makra bez parametrů se provádí takto: identifikátor_makra

Makra s parametry

Obsahují formální parametry se kterými se v textu makra dále pracuje. Používají se mnohdy místo funkcí. Narozdíl od funkcí jsou rychlejší a za formální parametry mohou být načteny hodnoty libovolných datových typů. Ustáleným pravidlem je psát identifikátor malými písmeny. Obecný zápis je takovýto: #define identifikátor_makra(seznam formálních parametrů) text_makra Volají se následovně: identifikátor_makra(seznam skutečných parametrů) V tomto programu je shrnuta práce s makry na jednoduchém výpočtu objemu válce. Obsahuje makra s a bez parametru, vnořování maker a zápis makra na více řádků

#include <stdio.h> 
#define PI 3.141592653 
#define na_2(x) (x)*(x) 
#define obem_valce(r,v) PI*na_2(r)*v 
#define oddelovac for(i=1;i<=40;i++) printf("*");\ 
    printf("\n");
float polomer,vyska; 
int i; 
int main(){
  oddelovac printf("Zadej polomer a vysku valce\n"); 
  oddelovac scanf(" %f %f",&polomer,&vyska); 
  oddelovac printf("Obem valce je %.2f * %.2f * %.2f =
  %.2f\n",PI,na_2(polomer),vyska,obem_valce(polomer,vyska)); 
  oddelovac getch(); 
  return;
}

Vkládání souborů

Proto abychom mohli do našeho souboru se zdrojovým kódem připojit další soubory, ať už knihovny funkcí či další části našeho programu používáme tyto dva zápisy příkazu #include: #include #include „název_souboru“ První zápis znamená že soubor název_souboru je hledán ve standardním adresáři pro include. Takto se zpravidla začleňují standardní hlavičkové soubory. Není-li soubor nalezen, je ohlášena chyba. Druhý zápis znamená že soubor název_souboru je hledán v pracovním adresáři. Není-li tam nalezen, postupuje se podle první možnosti. Takto se zpravidla začleňují uživatelské hlavičkové soubory.

Alokace paměti

Alokace paměti je vymezení místa v paměti pro proměnnou. Každé proměnné musí být během své existence přidělen paměťový prostor, který je dán datovým typem. Jméno proměnné je vlastně symbolická adresa tohoto prostoru. Data dělíme na: statické a dynamické

Statické

sou to data u nichž známe v době překladu jejich velikost a identifikátor. Jsou to globální proměnné, které mají tu vlastnost, že se automaticky nulují, vznikají spuštěním programu a zanikají na jeho konci. Ke statickým proměnným se řadí také lokální proměnné, které mají tu vlastnost, že nejsou automaticky nulované a jejich platnost končí koncem funkce či bloku.

Dynamické

Dynamické data jsou data které nemají předem stanovenou velikost. Alokaci provádíme speciálním příkazem za běhu programu. Dynamické proměnné nemají svůj identifikátor. Přistupujeme k nim pomocí pointerů.

Paměťové třídy

Kromě identifikátoru a datového typu jsou proměnné určeny ještě paměťovou třídou, které náleží. Paměťová třída určuje kde bude proměnná v paměti uložena, jakou bude mít viditelnost a jakouživotnost. Paměťové třídy se zapisují v následujícím formátu: název_pam_třídy datový_typ identifikátor_proměnné; Existují tyto paměťové třídy: auto, extern, statis, register auto Paměťová třída je implicitně používána pro všechny lokální proměnné. Paměť se pro ně alokuje automaticky až při vstupu do bloku, ve kterém jsou definovány. Po opuštění bloku je tato paměť zase uvolněna. Tato proměnná je viditelná jen v rámci bloku, ve kterém je definována. Existuje– li vedle této automatické proměnné i nějaká globální proměnná se stejným identifikátorem, je zastíněna automatickou proměnnou.

extern

Implicitní paměťová třída pro globální proměnné. Má využití při odděleném překladu. Je-li třeba, aby dva či více modulů sdílelo tutéž proměnnou v jednom souboru bude definována proměnná bez slova extern a ve všech ostatních zapíšeme klíčové slovo extern. Proměnné s paměťovou třídou extern nelze inicializovat! static Tato paměťová třída je použitelná jak pro lokální tak pro globální proměnné. Statické lokální proměnna je viditelná jen ve funkci, kde je definována. Paměť pro takovou proměnnou je alokována při spuštění dané funkce a uvolněna je až po skončení programu. Z toho vyplývá, že, máme-li statickou proměnnou a opustíme blok, ve kterém byla definována, tato proměnná nezaniká, pouze již není viditelná (ponechává si svou hodnotu mezi jednotlivými voláními funkce) Pro globální proměnné má paměťová třída static poněkud odlišný význam. Používá se při odděleném překladu. Při jejím použití by jsme nadefinovali globální neexportovatelnou proměnnou. To znamená že globální proměnné paměťové třídy static jsou viditelné pouze v modulu ve kterém jsou definovány. register Používá se pro lokální proměnné. Proměnná je viditelná pouze v bloku ve kterém je definována. Je alokována do registru, není-li v něm místo alokuje se do zásobníku. Pro nejasnost alokace nelze použít operátor adresy &. Jelikož třída register zvyšuje rychlost přístupu, používá se pro často používané proměnné (např. řídící proměnné cyklu). Program ukazuje použití modifikátoru register a static pro lokální proměnné.

#include <stdio.h> 
void fce(void); 
int main()
{ 
   register int i; 
   for(i=0;i<5;i++) fce(); 
   getch(); 
   return;
} 
void fce(void)
{ 
   static int x=0; 
   x++; 
   printf("Funkce byla volana %dx \n",x);
}

Pointery

Ukazatel (pointer) je v Céčku statická celočíselná proměnná obsahující adresu jiné statické či dynamické proměnné. Nese sebou současně informaci o datovém typu, který se na této adrese nachází. Pointer na proměnnou určitého datového typu se deklaruje pomocí operátoru dereference ‚*‘: datový_typ *identifikátor_pointeru; Uložení adresy do pointeru se liší dle toho zda pointer ukazuje na statickou či dynamickou proměnnou. Díky operátoru reference ‚&‘ uložíme do pointeru adresu statické proměnné: identifikátor_pointeru=&identifikátor_proměnné;

A takto do pointeru uložíme adresu a vyalokujeme prostor pro dynamickou proměnnou: identifikátor_pointeru=(datový_typ *)malloc(sizeof(datový_typ)); Výše uvedený zápis se dá přeložit následovně. Funkce malloc() je funkce, která alokuje paměťový prostor v haldě. Jejím parametrem je počet bytů potřebný pro alokaci. Ten jsme zjistili operátorem pro zjištění velikosti datového typu sizeof(). Jelikož funkce malloc() vrací ukazatel na datový typ void (generický pointer na libovolný datový typ) je nutné tento pointer přetypovat pomocí operátoru přetypování (datový_typ *). V případě, že se nepodaří požadovanou paměť alokovat, vrací funkce hodnotu NULL. Proto lze do programu zapsat následující test zda alokace proběhla: if(identifikátor_pointeru==NULL) printf(„Chybna alokace pameti\n“);
Pro samotné uložení hodnoty na místo kde ukazuje pointer se používá tento zápis: *identifikátor_pointeru=hodnota; Při použití pointeru na dynamickou proměnnou se musíme po ukončení práce s pointerem postarat o uvolnění paměti: free(identifikátor_pointeru); A proto aby pointer neodkazoval na místo, které již neexistuje měli bychom ho ukotvit: identifikátor_pointeru=NULL; Následující příklad ukazuje jak pracovat s dynamickými pointery.

#include <stdio.h> 
int main(){ 
   float *a,*b; 
   a=(float *)malloc(sizeof(float)); 
   b=(float *)malloc(sizeof(float)); 
   printf("Zadej dve cisla\n"); 
   scanf("%f %f",a,b); 
   (*a > *b)?printf("%f je vetsi nez %f \n", *a, *b):printf("%f je mensi nez %f \n",   *a, *b); 
   printf("Soucet: %.2f\n",*a+*b); 
   printf("Rozdil: %.2f\n",*a-*b); 
   printf("Soucin: %.2f\n",*a**b); 
   printf("Podil: %.2f\n",(*a)/(*b)); 
   getch(); 
   return;
}

Pointery a funkce

Pomocí pointerů realizujeme funkce které vracejí více hodnot. Realizuje se to pomocí
proměnných, které jsou vně funkce a my s nimi ve funkci můžeme pomocí pointerů pracovat neboli přidat jim určitou hodnotu. Hovoříme o formálních parametrech volaných adresou. V kapitole Funkce jsme vždy používali tzv. formální parametry volané hodnotou, které nemají vliv na skutečný parametr. Definice funkce, která vrací více hodnot by mohla vypadat takto: návratový_typ identifikátor_fce(formální parametry, dat_typ *pointer) { .. .
*pointer=výstupní_hodnota; return návratová_hodnota; }
A v programu by jsme takovouto funkci volali následovně: identifikátor_fce(skutečné parametry, &identifikátor_proměnné); Následující program demonstruje použiti pointerů realizujících návrat více hodnot z funkce.

#include <stdio.h> 
void vypocty(int a, int b, int *sou, int *roz, int *souc, float *pod); 
int main()
{ 
   int x,y,soucet,rozdil,soucin; 
   float podil; 
   printf("Zadejte prosim dve cela cisla\n"); 
   scanf("%d %d",&x,&y); 
   vypocty(x,y,&soucet,&rozdil,&soucin,&podil); 
   printf("%d + %d = %d\n",x,y,soucet); 
   printf("%d - %d = %d\n",x,y,rozdil); 
   printf("%d * %d = %d\n",x,y,soucin); 
   printf("%d / %d = %.2f\n",x,y,podil); 
   getch(); 
   return;
} 
void vypocty(int a, int b, int *sou, int *roz, int *souc, float *pod)
{ 
   *sou=a+b; 
   *roz=a-b; 
   *souc=a*b; 
   *pod=(float)a/b; 
   return;
}

Pole

Je strukturovaný homogenní datový typ. To znamená že, obsahuje několik prvků stejného datového typu se kterými můžeme pracovat. Pole je v podstatě pointer obsahující adresu nultého prvku pole. Může být statické či dynamické. Statické pole U statického pole je nutné znát počet prvků během překladu. Deklarujeme ho následovně dat_typ identifikátor[počet_prvků]; Pole může nabývat hodnot kteréhokoli základního datového typu. K hodnotám pole přistupujeme pomocí indexů. Jelikož C indexuje od nuly můžeme přistupovat k prvkům od indexu 0 až počet_prvků-1. Takový přístup by vpadal takto: identifikátor[index]

Hodnoty pole pod jednotlivými indexy jsou v paměti ukládány za sebou. Je třeba si uvědomit, že překladač jazyka C neprovádí kontrolu mezí. Proto je možné pracovat indexy pole, které jsou větší než námi nadefinovaný nejvyšší index. To ovšem může způsobit katastrofální následky, jelikož pracujeme s části paměti, která nebyla alokována. Pole je možno hned při deklaraci inicializovat: dat_typ identifikátor[počet_prvků]={hodnota_1, hodnota_2, …}; Chceme-li pole setřídit použijeme nějakou třídící metodu. Nejjednodušší, ale zároveň docela pomalou je Bubble Sort:

for(i=0; i<pocet_prvku-1;i++)
for(j=0; j<pocet_prvku-1;j++)
if(pole[j]<pole[j+1]){ pom=pole[j];
pole[j]=pole[j+1];
pole[j+1]=pom;
}

Dynamické pole

Není nutné znát během překladu počet prvků, můžeme je vyalokovat až při samotném běhu programu. Při překladu je ovšem nutné znát bázový typ pole. Deklaruje se stejně jako pointer, tedy takto: dat_typ *identifikátor; Alokace pole se obecně zapisuje následně: identifikátor=(datový_typ *)malloc(sizeof(datový_typ)*počet_prvků); Samotná práce s dynamickým polem je shodná s prací se statickým polem. Dynamické pole ovšem musíme jakožto dynamickou proměnnou uvolnit: free(identifikátor); a také zakotvit: identifikátor=NULL; Příklad pro práci s dynamickým polem je obdoba příkladu pro statické pole:

#include <stdio.h> 
int main()
{ 
   int i,j,*pole,pocet,max,min,sum=0,pom; 
   printf("Zadej pocet prvku pole: "); 
   scanf("%d",&pocet); 
   pole=(int *)malloc(sizeof(int)*pocet); 
   printf("Zadavej prvky pole: \n"); 
   for(i=0;i!=pocet;i++) scanf("%d",&pole[i]); 
   max=pole[0]; 
   min=pole[0]; 
   for(i=0;i!=pocet;i++) 
   { 
      if(pole[i]>max) max=pole[i]; 
      if(pole[i]<min) min=pole[i]; 
      sum+=pole[i]; 
   }
   printf("\nMaximum je %d\n",max); 
   printf("Minimum je %d\n",min); 
   printf("Stredni hodnota je %.2f\n",(max+min)/2.0); 
   printf("Aritmetricky prumer je %.2f\n",(float)sum/i);
   for(i=0;i!=pocet-1;i++) 
   for(j=0;j!=pocet-1;j++) if(pole[j]>pole[j+1]) { 
      pom=pole[j+1]; 
      pole[j+1]=pole[j]; 
      pole[j]=pom; 
   }
   printf("\nSetrizene pole: "); 
   for(i=0;i!=pocet;i++) printf("%d ",pole[i]); 
   free(pole); 
   pole=NULL; 
   getch(); 
   return;
}

Pole a funkce

Je-li proměnná typu pole (tzn. ukazatel na první prvek) parametrem funkce užíváme adresu pole
(volání odkazem). To proto aby se změna pole zachovala i po návratu z funkce. Obecný zápis hlavičky funkce jejíž parametr je statické pole je takovýto: dat_typ id_fce(dat_typ pole[], int pocet, …) Hlavička funkce jejíž parametr je dynamické pole s e zapisuje obdobně: dat_typ id_fce(dat_typ *pole, int pocet, …) Z těchto zápisů je zřejmé, že je nutné zavést jako parametr funkce taky celočíselnou proměnnou pocet, která uchovává informaci o počtu prvků pole a slouží tak pro kontrolu mezí. Volání funkce v hlavní části programu se provádí takto: id_fce(pole,pocet, …); Pro ilustraci pole jakožto parametru funkce je užit příklad pro statické pole s tím, že načítání, výpis, setřízení a zjišťování maxima a minima je zajištěno funkcemi.

#include <stdio.h> 
#define POCET 8 const nil=0; 
void nacti(int pole[], int poc); 
void vypis(int pole[], int poc); 
void zjisti(int pole[], int poc, int *max, int *min, int *sum); 
void setrid(int pole[], int poc); 
int main()
{ 
	int pole[POCET],max,min,soucet=0; 
	printf("Zadej prvky pole:\n"); 
	nacti(pole,POCET); max=pole[nil];
	min=pole[nil]; 
	zjisti(pole,POCET,&max,&min,&soucet); 
	printf("\nMaximum je %d\n",max); 
	printf("Minimum je %d\n",min); 
	printf("Stredni hodnota je %.2f\n",(max+min)/2.0); 
	printf("Aritmetricky prumer je %.2f\n",(float)soucet/POCET); 
	printf("\nSetrizene pole:\n"); 
	setrid(pole,POCET); 
	vypis(pole,POCET); 
	getch(); 
	return;
} 
void nacti(int pole[], int poc)
{
	int i; 
	for(i=nil;i<poc;i++) scanf("%d",&pole[i]); 
	return;
} 
void vypis(int pole[], int poc)
{
	int i; 
	for(i=nil;i<poc;i++) printf("%d ",pole[i]); 
	return;
} 
void zjisti(int pole[], int poc, int *max, int *min, int *sum)
{
	int i; 
	for(i=nil;i!=poc;i++) { 
		if(pole[i]>*max) *max=pole[i];
	if(pole[i]<*min) *min=pole[i]; 
	*sum+=pole[i]; 
	}
	return;
} 
void setrid(int pole[], int poc) 
{
	int i,j,pom; 
	poc--; 
	for(i=nil;i!=poc;i++) 
	for(j=nil;j!=poc;j++) 
	if(pole[j]>pole[j+1]) { 
		pom=pole[j+1]; 
		pole[j+1]=pole[j]; 
		pole[j]=pom; 
	}
	return; 
}

Matice

Je to pole polí, přičemž prvky jsou uloženy v paměti za sebou. Indexuje se od nuly. Deklaruje se takto: dat_typ id_matice[řádky][sloupce]; Inicializuje se tímto způsobem: id_matice[][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12},…}Z tohoto zápisu vyplývá že uvedení počtu sloupců je povinné, uvedení počtu řádků je nepovinné.

Dynamická matice se realizuje třemi způsoby: jako pole pointerů, pointer na pole nebo pointer na pointer.

Pointer na pole

Je realizováno pomocí ukazatele který ukazuje na souvislý blok v haldě. Při deklaraci je nutné znát počet sloupců na řádek. Deklarace je takováto: dat_typ (id_pole)[počet_sloupců]; Alokace v dynamické paměti se zapisuje takto: id_pole=(typ ()[])malloc(sizeof(typ)počet_sloupcůpočet_řádků); Po ukončení práce je nutné místo v paměti odalokovat a pointer ukotvit: free(id_pole); id_pole=NULL;

#include <stdio.h> 
#define S 3
int main()
{ 
	int i,j; 
	int (*matice)[S]; /* pocet sloupcu je znam pri prekladu */
	srand((long)time(NULL)); 
	printf("\nMatice - pointer na pole:"); 
	printf("\n");
	matice=(int(*)[])malloc(2*S*sizeof(int));
	for (i=0;i<2;i++)
	{
		for (j=0;j<S;j++)
		{
			matice[i][j]=rand()%100; printf("%4d",matice[i][j]);
		} 
		printf("\n");
	}
	getch(); 
	return 0;
}

Pointer na pointer

Je to pointer který ukazuje na dynamické pole pointerů v haldě (symbolizuje řádků), jednotlivé prvky pole obsahují pointery ukazující na další dynamické pole (symbolizuje sloupce). Jednotlivé řádky nemusí být v paměti uloženy za sebou. Deklaruje se takto: dat_typ **id_pole; Pro alokaci dynamického pole symbolizující počet řádků se užije tento zápis: id_pole=(typ **)malloc(sizeof(typ *)*počet_řádků); Alokace jednotlivých řádků se zapíše následně: id_pole[index]=(typ *)malloc(sizeof(typ)*počet_sloupců); Ukončení-li práci odalokujeme oblast v dynamické paměti, která zabírá jednotlivé řádky: free(id_pole[index]); Poté musíme odalokovat pole obsahující pointery: free(id_pole); A pak už jen ukotvit pointer id_pole=NULL;

#include <stdio.h> 
int main()
{ 
	int i,j; int **matice; /* pocet radku, sloupcu neni znam pri prekladu */
	srand((long)time(NULL)); 
	printf("\nMatice - pointer na pointer:"); 
	printf("\n");
	matice=(int**)malloc(2*sizeof(int*)); /* radky */
	matice[0]=(int*)malloc(3*sizeof(int)); /* pocet prvku na radce */ 
	matice[1]=(int*)malloc(3*sizeof(int));
	for (i=0;i<2;i++)
	{ 
		for (j=0;j<3;j++)
		{
			matice[i][j]=rand()%100; 
			printf("%4d",matice[i][j]);
		} 
		printf("\n");
	}
	getch(); 
	return 0;
}

Řetězce

V jazyku C není definován datový typ řetězce, místo toho je využíváno pole znaků ukončené nulovým znakem, čili znakem s ASCII hodnotou nula (Zapisujeme ho takto: ‚\0‘). Skutečnost ukončení nulovým znakem znamená, že musíme nadefinovat pole o jeden byte delší, aby zbylo místo pro nulový znak. Řetězec deklarujeme takto: char id_řetězce[velkost]; Inicializovat lze dvěma způsoby, buď takto: char id_řetězce[]={‚a‘,’h‘,’o‘,’j‘,’\0′}; nebo takto: char id_řetězce[]=“ahoj“; Tento zápis je zcela ekvivalentní s předchozím. Pro pole je vyhrazeno 5 bytů, do kterých je uložen řetězec „ahoj“ včetně nulového znaku. Načítání a výpis řetězce můžeme provádět pomocí scanf() a printf(), ale taky pomocí funkcí přímo určených pro čtení a výpis řetězců gets() a puts(). Funkce gets() při načítání čte narozdíl od scanf(), která načítá pouze po první výskyt bílého znaku, vše co zapíšeme. Práce s řetězcem je shodná jako práce s polem, lze tedy například užít pointerovou aritmetiku.

Funkce pro řetězce

Pro řetězec jsou v C předdefinovány funkce strcpy(),strcat(),strcmp(),strlen(). Pro jejich použití je nutno připojit hlavičkový soubor string.h.

strcpy() Slouží pro překopírování obsahu zdroje do cíle, přičemž zdroj zůstane nezměněn. Musíme zajistit to aby byl cíl dostatečně velký. Má obecný tvar: strcpy(zdroj,cíl);

strcat() Slouží pro přidávání obsahu zdroje k obsahu cíle (zřetězení). Musíme zajistit to, že je cílové pole dostatečně velké. Obecný zápis: strcat(zdroj,cíl);

strcmp() Funkce porovnává dva řetězce. Řetězce jsou porovnávány lexikograficky, tj. ve slovníkovém pořadí. Jsou-li řetězce shodné, vrací funkce nulu. Je-li první větší než druhý, vrací 1 a je-li první menší než druhý vrátí funkce -1. Obecný zápis: strcmp(řetězec_1,řetězec_2);

strlen() Tato funkce vrací délku řetězce ve znacích. Do délky řetězce se nezapočítává koncový nulový znak. Zapisuje se následně: strlen(řetězec); Příklad uvedený níže ukazuje varianty načítání řetězce, zjišťování délky a porovnání.

#include <stdio.h> 
#include <string.h> 
int main()
{ 
	int indikace; 
	char retezec_1[20],retezec_2[20],vysledek; 
	gets(retezec_1); 
	scanf("%s",retezec_2); 
	printf("retezec_1 (%s) ma delku %d\n",retezec_1,strlen(retezec_1)); 
	printf("retezec_2 (%s) ma delku %d\n",retezec_2,strlen(retezec_2)); 
	indikace=strcmp(retezec_1,retezec_2); 
	if(indikace==0) puts("Retezce jsou shodne"); 
	else if (indikace==1) puts("retezec_1 je lexikograficky vetsi nez retezec_2"); 
	else if (indikace==-1) puts("retezec_2 je lexikograficky vetsi nez retezec_1");
	getch(); 
	return;
}

Soubory

V programovacím jazyku C se provádí diskové I/O pomocí logického rozhraní nazývaného datový proud. Datové proudy mají podobné vlastnosti a jsou zpracovávány stejnými I/O funkcemi. Soubor je skutečný fyzický výskyt, který přijímá nebo poskytuje data. V C existují dva typy souborů. Textový a Binární, liší se použitím I/O funkcí. Základní rozdíl mezi těmito dvěma typy souborů je v tom, že v binárním souboru jsou data ukládána stejným způsobem jako v paměti. Kdežto do textového souboru se musí data převést na posloupnost znaků. V hlavičkovém souboru stdio.h je pro práci s nimi zaveden datový typ FILE, který je strukturou obsahující různé informace o souboru, například velikost, aktuální pozici a jeho přístupové režimy, které určují jak k souboru přistupovat. Proměnnou soubor si nadeklatujeme jako ukazatel na typ FILE. FILE *id_souboru Před tím než budeme se souborem pracovat musíme ho nejdřív otevřít. To provedeme pomocí funkce fopen(), která vrací ukazatel na daný soubor. Je-li tato funkce neúspěšná, vrací NULL. id_souboru=fopen(„jméno.přípona“,“režim“); Pro textové souory existují následující režimy:

režimvýznamrežim pro binární soubory
rotevře textový soubor pro čtenírb
wvytvoří textový soubor pro zápis (přepíše existující)wb
aotevře textový soubor pro připisováníab
R+otevře textový soubor pro čtení/zápisrb+
W+vytvoří textový soubor pro čtení/zápiswb+
A+otevře textový soubor pro čtení/připisováníab+

Pokud soubor neexistuje, při většině režimech se vytvoří. Pouze při r,r+,rb,rb+ se soubor nevytvoří a fopen() selže. Jelikož operace otevření nemusí proběhnout je vhodné ji ošetřit testem a raději používat tento zápis: if(id_souboru=fopen(„jméno.přípona“,“režim“)==NULL){printf(„Chyba pri otevreni souboru“); return;} Pro ukončení práce se souborem použijeme funkci fclose(), která zavře soubor a odpojí datový proud. Je nutné soubor zavřít jestliže chceme ať se v něm projeví změny. fclose(id_souboru); Při úspěchu vrací nulu, při chybě vrací symbolickou konstantu EOF. Pro kontrolu úspěšnosti je vhodnější používat tento zápis: if(fclose(soubor)==EOF){printf(„\nChyba pri uzavreni souboru“); return;} Další funkce souborového systému Patří mezi ně funkce rename(), remove(), rewind(), feof() a fflush().

rename() Slouží pro přejmenování souboru. Obecně se zapisuje: rename(„staré_jméno“,“nové_jméno“); Při úspěchu vrací funkce nulu, při neúspěchu nenulovou hodnotu.

remove() Smaže daný soubor. Zápis je: remove(„jméno_souboru“); Při úspěchu vrací funkce nulu, při neúspěchu nenulovou hodnotu.

rewind() funkce přesune aktuální pozici v souboru na jeho začátek.

rewind(id_souboru); Je bez návratové hodnoty jelikož každý úspěšně otevřený soubor lze nastavit na začátek.

feof() Tato funkce se používá k zjišťování konce souboru. Je-li aktuální pozice na konci vrací nenulovou hodnotu. Jestliže ne vrací nulu. feof(id_souboru);

fflush() Funkce slouží k vyprázdnění diskového bufferu. fflush(datový_proud) Využívá se pro vyprázdnění standardního datového proudu pro čtení z klávesnice stdin (standardní vstup).

Pro souborový vstup/výstup znaku se užívají funkce getc(), putc(). Tento postup se užívá jak pro textové, tak pro binární soubory getc() nebo fgetc() Tato funkce je určena pro vstup znaků ze souboru. Zapisuje se takto: fgetc(id_souboru); Má jediný parametr typu ukazatel na FILE, návratovou hodnotou této funkce je kód znaku, přečtený z určeného souboru. Při konci souboru či chybě vrací symbolickou konstantu EOF. putc() nebo fputc() Funkce je určena pro výstup znaků do souboru. fputc(znak,id_souboru); Má jako první argument kód znaku, který má být zapsán do souboru, který je identifikován druhým parametrem. Návratová hodnota funkce je kód zapsaného znaku, nebo EOF pokud při výstupu došlo k chybě. V následující ukázce nejprve zapíšeme do souboru text a poté se vytvoří kopie tohoto souboru.

#include <stdio.h> 
#include <conio.h>
int main(void)
{ 
	FILE *fr,*fw; char c;
	fw=fopen("original.txt","w"); 
	printf("Zapiste text ukonceny '.'\n"); 
	do 
	{ 
		scanf("%c",&c); 
		putc(c,fw);
	} while (c!='.'); 
	fclose(fw);
	fr=fopen("original.txt","r"); 
	fw=fopen("kopie.txt","w"); 
	while (feof(fr)==0) putc(getc(fr),fw); 
	fclose(fr); 
	fclose(fw);
	printf("\nSoubor byl zkopirovan!"); 
	fflush(stdin); 
	getch(); 
	return(0);
}
Back to Top