Tvorba programu - algoritmizace a programování

01-Tvorba programu

Postup při řešení problému

  1. Shora dolů - rozklad úlohy na segmenty, které se neustále zjemňují, až můžeme řešit problemativu v konkrétním programovacím jazyce.
  2. Zdola nahodu - z elementárních kroků vytváříme prostředky ke zvládnutí problému
  3. oba současně

Definice algoritmu

Algoritmus

Tvorba algoritmů S algoritmy se setkáváme v běžném životě. Těmito algoritmy jsou například recepty na vaření, postup ovládání video kamery, cesta do školy.

Vlastnosti algoritmů "HERgoD"

  1. Hromadnost – algoritmus musí být použitelný pro všechny úlohy stejného typu (dva lidé dojdou podle stejného popisu na stejné místo)
  2. Elementárnost - algoritmus se skládá z konečného počtu jednoduchých kroků (elementy: chůze, jízda autobusem)
  3. Resultativnost – od libovolných vstupních dat musíme dospět k požadovaným výsledkům (vždy dojdeme k výsledku - nezasekneme se uprostřed)
  4. Konečnost – činnost algoritmu skončí v reálném čase
  5. Determinovanost – v každém kroku je znám následující krok (člověk vystoupí z autobusu a ví, že jde na nějaké místo)

Program

Možnosti zápisu algoritmu:

  1. Slovně - návody k obsluze, recepty, postup práce
  2. Graficky - vývojové diagramy a strukturogramy.
  3. Pomocí programovacího jazyka
  4. Matematicky

Ke kreslení vývojových diagramů používáme standardní grafické symboly:

Jednotlivé značky spojujeme čárami a spojkami:

Zpracování programu

Integrované vývojové prostřední (IDE - integrated development enviroment) = soubor programů, které si volám podle toho, co potřebuju.
EPiC LeaDeR:

  • Editor
  • Preprocesor
  • Compiler
  • Linker
  • Debugger
  • Run - spuštění

Preprocesor

  1. Vkládá knihovny (#include...)
  2. Odstraňuje komentáře
  3. Rozvíjí makra (s parametrem / bez parametru, projde a nahradí)
  4. Zpracovává podmíněný překlad (nástroj k testování určité části programu - ostatní je jako vykomentováno)

Příkazy pro něj začínají "#" typicky incude: když ho najde, vyhodí ten řádek a vloží tam tu dotyčnou knihovnu.
V hlavičkových souborech nejčastěji: deklarace fcí, maker, konstant. "<>" zobáčky znamenají, že se includy hledají v defaultním místě standartních inkludů. Jiná možnost: napsat do uvozovek - hledá se v aktuálním adresáři: "C:\prg\headfile.h" nedávají se znaky "\" dvakrát, bo to není string!

Kompiler

Přeloží každý soubor programu - výsledkem je *.OBJ (object module - binární soubor) v TurboC++, DevC++ *.o. V OBJ nejsou odvolávky z knihoven, kontroluje syntaktické chyby. Tyto soubory si předávají členové týmu, protože neodhaluje know-how.

  • Syntaxe - pravidla zápisu, pravidla jazyka - lze dohledat v dokumentaci jazyka
  • Sémantika - význam napsaného kódu

Linker

Poskládá OBJ moduly s knihovnami a vytvoří *.exe soubor. Také vkládá absolutní adresy paměti.

Debugger

Ladící prostředek součástí IDE. Hledá běhové chyby při spuštěném programu. Umí breakpointy a skoky po instrukcích.

Řídící struktury - větvení

02-Větvení

Typy podmíněných

  • if-else
  • switch
  • Ternární operátor

Konstrukce if

Příkaz if provádí příkazy podle toho, zda byla nebo nebyla splněna zadaná podmínka.

if (x == 0) printf("Proměnná x je nula.\n");
if (x > 0) printf("x je kladné\n");
else printf("x není kladné\n");

Konstrukce switch

Příkaz switch slouží k větvení programu do libovolného počtu větví v závislosti na předaném celočíselném výrazu. Jednotlivé větve tohoto příkazu se provádějí, má-li předaný výraz jim odpovídající hodnotu. Nelze zde tedy vytvářet libovolné podmínky. V konstrukci switch lze od selektoru definovat také default větev, která se bude provádět, pokud výraz nenabude žádné z uvedených hodnot.

switch (cislo){
  case 1: printf("cislo je 1\n");
          break;
  case 2: printf("cislo je 2\n");
          break;
 default: printf("neco jineho\n");
}

Vynecháním příkazů break na konci jednotlivých větví je pokračuje v provádění dalších větví.

switch (cislo){
  case 1:
  case 2: printf("cislo je 1 nebo 2\n");
          break;
 default: printf("neco jineho\n");
}

Ternární operátor

má stejný význam jako příkaz if-else, jen syntaxe je jiná. Ternární, protože má jako jediný operátor 3 operandy.

vyraz_podm ? vyraz_1 : vyraz_2;
i = (a != 0) ? 5 : 10;
  // Pokud je a ruzne od 0, i bude rovno 5
  // V opacnem pripade bude i rovno 10

Grafický zápis:

  • Úplná
  • Neúplná
  • Vícenásobná

Grafický zápis vývojového diagramu je dán státní normou. Pokud je větvení neúplné, pak na straně, kde podmínka neplatí je prázdno.

Řídící struktury - cykly

03-Cykly

Typy a charakteristika cyklů

  • while / for (cyklus s podmínkou na začátku)
  • do-while (cyklus I s podmínkou na konci)

Cykly jsou strukturované příkazy, které při splnění (nebo nesplnění) podmínky provádí příkazy obsažené v tělě cyklu znovu a znovu. Jednotlivé průchody tělem cyklu označujeme jako iterace.
Někdy potřebujeme provádění cyklu ukončit předčasně. K tomu můžeme použít příkaz break. Jestliže potřebujeme předčasně ukončit jednotlivou iteraci (vynechat při průchodu zbytek těla cyklu), můžeme použit příkaz continue.

Příkaz while

Příkaz while představuje cyklus s podmínkou na počátku.

while ( podmínka ) příkaz

Kde příkaz je tělo cyklu. Podmínka je výraz, který lze implicitně převést na typ bool. Podmínka může obsahovat deklaraci proměnné (jen v C++) a tato proměnná bude lokální v těle cyklu.

Význam příkazu while:
Nejprve se vyhodnotí podmínka. Je-li nepravdivá, tělo cyklu se neprovede a provádění příkazu while skončí.
Je-li podmínka splněna, provede se příkaz tvořící tělo cyklu. Poté se opět vyhodnotí podmínka atd.
Podmínka opakování se tedy vyhodnocuje před každou iterací. Není-li podmínka před prvním průchodem splněna, neprovede se tělo cyklu while ani jednou.

Příkaz do-while

Zkráceně označovaný jako příkaz do. Je to cyklus s podmínkou na konci.

do příkaz while ( podmínka );

Podmínka je výraz, který lze implicitně převést na typ bool. Výraz zde nemůže obsahovat deklaraci!

Význam příkazu do:
Nejprve proběhne tělo cyklu, tedy příkaz. Pak se vyhodnotí výraz. Pokud je roven false, znamená to, že podmínka opakování není splněna a provádění příkazu do skončí. V opačném případě se opět provede tělo cyklu a znovu se testuje podmínka opakování atd. To znamená, že tělo cyklu se provede vždy alespoň jednou.

Příkaz for

for ( inicializační_příkaz ; podmínka ; krok ) příkaz

Inicializační_příkaz je příkaz, který chceme provést před vstupem do cyklu. Může obsahovat deklaraci (C++) a může být prázdný (tj. obsahuje pouze středník).
Podmínka může obsahovat deklaraci a také zde můžeme zapsat prázdný výraz. Krok předepisuje změny proměnných, které je třeba po průchodu tělem cyklu udělat. I tento výraz může být prázdný.
Proměnné, deklarované v inicializačním_příkazu a v podmínce, jsou lokální v těle cyklu. Přesněji: Proměnné, deklarované v inicializačním_příkazu, můžeme použít v podmínce, v kroku a v těle cyklu. Proměnné, deklarované v podmínce, můžeme použít v kroku a v těle cyklu.

Příklad: Příkaz for se často používá při zpracování polí. Chceme-li např. vynulovat všechny prvky pole A o 100 prvcích, napíšeme:

const N = 100; int A [N] ;
// ...
for(int i = 0; i < N; i++) A[i] = 0;
for (;;) { //nekonečný cyklus; }
while(1) { //nekonečný cyklus; }

Poznámky k cyklům

  • Používat pouze jednu řídící proměnnou
  • Řídící proměnná ovlivňována pouze v řídící části cyklu a ne v těle cyklu.
  • Pokud má cyklus prázdné tělo, jeho ukončující středník je na nové řádce.
  • Continue lépe nahradit čitelnějším konstrukcí if-else.
  • Break by se měl vyskytovat jen v nejnutnějším případě a na jednom místě.
  • Přednost while a for před do-while, kvůli přehlednosti.

Grafický zápis

Příkazy break, continue

Příkaz break

Tento příkaz smíme použít jen v těle cyklu (for, while, do) nebo v těle příkazu switch; vvskytne-li se jinde, ohlásí překladač chybu.
Význam příkazu break:
Ukončuje nejvnitřnější neuzavřenou smyčku a hned opouští cyklus. A také obsáhleji:
Příkaz break způsobí ukončení příkazu cyklu nebo přepínače (switch), v jehož těle se vyskytl. Při několika do sebe vnořených příkazech do, while, for nebo switch způsobí ukončení nejvnitmějšího z nich, který tento příkaz break obklopuje.

Příkaz continue

Příkaz umožňuje předčasně ukončit daný průchod tělem cyklu (iteraci). Smí se vyskytnout pouze v těle cyklu (v příkazech for, do a while). Jeho použití kdekoliv jinde způsobí chybu.
Význam příkazu continue:
Skáče na konec nejvnitřnější neuzavřené smyčky a tím vynutídalší iteraci smyčky, cyklus neopouští. Také:
Příkaz continue přenese řízení na pokračovací část nej vnitřnějšího příkazu while, do nebo for, v jehož těle se vyskytl. To znamená, že ukončí právě probíhající iteraci a způsobí vyhodnocení podmínky pro pokračování (a v cyklu for ještě reinicializaci, tedy vyhodnocení výrazu).

Příkaz return

Význam příkazu return:
Příkaz return ukončí provádění těla funkce, v níž se nachází, a vrátí řízení funkci volající.
První varianta, ve které není uveden výraz, se používá ve funkcích typu void (které nevracejí žádnou hodnotu, tedy v procedurách). Uvedeme-li výraz, vrátí funkce hodnotu tohoto výrazu. Typ výrazu musí být možné implicitně převést na typ vracené hodnoty uvedený v deklaraci funkce, podobně jako např. při přiřazení.

Funkce typu void nemusí příkaz return obsahovat. Dojde-li řízení v těle funkce až ke složené závorce „}“ ukončující její tělo, je to stejné, jako kdyby zde byl zapsán příkaz return; (bez výrazu).

Z funkcí jiného typu (tj. z funkcí, které vracejí nějakou hodnotu) se musíme vždy vrátit pomocí příkazu return s výrazem odpovídajícího typu.

Datové typy a proměnné v jazyce C a C++

04-Datové typy

Rozdělení typů

  • jednoduché
    • celočíselné
      • char (1B)
      • short (2B)
      • int (podle prostředí)
      • long (4B)
      • enum (pojemnované konstanty, třeba PI)
      • boolean (u C++)
    • reálné
      • float (4B)
      • double (8B)
      • long double (10B))
    • void
  • strukturované
    • struktura
    • pole (nemá uvozovací slovo)
    • řetězec
    • třída
    • union
    • file (také struktura, ale říkáme, že je nový datový typ)

Co určuje datový typ:

  • velikost v paměti
  • množina hodnot (celá čísla v jakém rozsahu)
  • množina operací, kterou můžu udělat

Celočíselné typy

Tvoří dvě základní skupiny — typy „se znaménkem“ a „bez znaménka“. Celočíselné typy se znaménkem mohou obsahovat jak kladná tak i záporná čísla, zatímco typy bez znaménka mohou obsahovat pouze kladná čísla a 0.
Celočíselné typy se znaménkem jsou signed char, short, int a long a ještě typ long long.
Celočíselné typy bez znaménka jsou unsigned char. unsigned short. unsigned. unsigned long a unsigned long long.

int má délku podle kompilátoru a to:

  • x16 = 2B
  • x32 = 4B
  • x64 = 8B

Znakové typy

V jazyce C++ máme k disposici 4 znakové typy

  • char
  • signed char
  • unsigned char
  • wchar.t

Typy char, unsigned char a signed char zabírají 1 B a slouží především pro práci s evropskými znaky. Typ wchar.t zabírá typicky 2B nebo 4B a používá se pro práci s asijskými znaky nebo s kódem UNICODE.

Se znaky zacházíme podobně jako s ostatními celočíselnými typy, to znamená, že je můžeme používat ve výrazech podobně jako celá čísla. Jediný zásadní rozdíl se týká vstupů a výstupů znaků pomocí objektových datových proudů (cin. cout atd.), kdy se hodnoty znakových typů chovají opravdu jako znaky, nikoli jako čísla.

Reálná čísla typy

Tyto typy specifikují určité konečné podmnožiny množiny reálných čísel. V paměti jsou tato čísla zpravidla uložena ve tvaru odvozeném od semilogaritmického zápisu, tedy od zápisu, jako je 6,27 x 10^12. (Počítač ovšem samozřejmě využívá dvojkovou soustavu.) Číslo 6,27 zde nazýváme "mantisa", číslo 12 "exponent". V C++ můžeme pro práci s reálnými čísly používat typy float, double a long double.

Řídící řetězce formátu

  • %c - znak
  • %d - celé číslo dekadické
  • %x - celé číslo vypsané HEXa
  • %f - vypiš jako float
  • %s - text
  • %ld - long dekadické
  • %u - celé číslo unsigned
  • %lf - double
  • %Lf - long double

Definování nových typů

Způsob pro zavedení nového datového typu založeného na struktuře lze provést pomocí klíčového slova typedef.
Nejúplnější definice vypadá takto:

typedef struct clovek
{
 char jmeno[50];
 int  vek;
 double hmotnost, vyska;
}CLOVEK;

Kde clovek je název struktury a CLOVEK název nového datového typu. Jinými slovy slovní spojení struct clovek vyjadřuje totéž, co jedno slovo CLOVEK a výše definované proměnné nyní mohu zavést i takto:

CLOVEK Jenda, Bara; 

Při použití typedef je třeba pojmenovat strukturu pouze v případě, že by některou z jejích složek byl pointer na ni samu. Jinak lze název struktury vynechat. Položka dané struktury nemůže být právě vytvářeného datového typu přesněji název typu každé položky musí být různý od jména struktury, která ji obsahuje, či od jména právě vytvářeného typu. Položka však může být typu pointer na strukturu ve které je obsažena (nikoli však pointer na typ, který vytváříme pomocí typedef ).
K jednotlivým položkám proměnných tohoto typu pak přistupuji takto:

strcpy(p_Bara->jmeno, "Bára Zvučná");
//nebo p_Bara->JMENO = "Bára Zvučná";
p_Bara->vek = 20;
printf("%d",p_Bara->vek);

Výčtový typ

enum den {
          pondeli, utery = 22, streda,
          ctvrtek, patek , sobota
         };
den dnes = streda;

Enum umožňuje pojmenovat číselné výrazy, např. dny v týdnu.

Struktura

struct Zamestanec
 {
  char jmeno[20];
  char prijmeni[30];
  unsigned plat;
 };

Union

union DoubleInt 
{
 double d;
 int i;
} di;

Jako struktura, ale pamatuje si pouze prvek, který byl nejpozději změněn.

Soubor

FILE *fw;

Proměnné v jazyce C a C++

05-Proměnné

Charakteristika

Poměnné — tedy pojmenovaná místa v paměti, do kterých ukládáme nějaké hodnoty. Každou proměnnou je třeba deklarovat, tj. oznámit překladači, jak se bude jmenovat a jaké hodnoty do ní budeme ukládat (jakého bude typu).

Globální proměnné

Bude dostupná ve všech funkcích v programu za místem své deklarace.

  • Definují se mimo funkce (tz. i mimo funkci main)
  • Automaticky se nulují
  • Paměť se alokuje na začátku programu a uvolňuje na konci (v datové oblasti)

Lokální proměnné

Jejich platnost je omezena na tělo funkce.

  • Definují se uvnitř bloku nebo funkce za { a jen v ní platí
  • Nenulují se automaticky
  • Paměť se alokuje a uvolňuje v průběhu programu (v zásobníku)

Inicializace při deklaraci znamená, že jsme proměnné přidělili počáteční hodnotu.
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.

Paměťové třídy

  • Určí, ve kterých částech paměti bude proměnná kompilátorem umístěna a kde bude viditelná (dostupná)
  • Rozšiřují použití lokálních a globálních proměnných
  • 4 typy: "LASER"
    1. auto
    2. static
    3. extern
    4. register

Auto

Implicitní paměťová třída pro lokální proměnné. Ukládají se na zásobník. Při každém vstupu má náhodnou hodnotu, proměnná existuje od vstupu do funkce a zaniká výstupem.

  • Je přímo nastavena pro lokální proměnné
  • Nepoužívá se

Static

Neexistuje implicitní definice. (nutné vždy uvést) Tato PT je uložena v datové oblasti. Využívají lokální proměnné uvnitř funkcí - ponechají si svou hodnotu mezi jednotlivými voláními funkce.
Existuje od prvního volání funkce až do ukončení programu. Není přístupná z vnějšku funkce.
Globální proměnné a funkce mohou být static, pak jsou viditelné jen v modulu, kde jsou definovány.

static int a;
static float f,g; //g není static!
  • Lok: Paměť se alokuje v datové oblasti, mezi dvěmi volání funkce si uchovává svou hodnotu
  • Glob: Je použitelná pouze v souboru, ve kterém ji definujeme
  • Glob: V každém modulu používáme vlastní globální proměnnou, vzájemně neovlivňují

Při prvním volání fce() se x vynuluje při každém volání funkce FCE se hodnota q zvýší o 1.

Extern

Implicitní PT pro globální proměnné. Je uložena v datové oblasti. Používá se pro oddělený překlad souborů. (2 a více souborů sdílí tuto proměnnou). V jednom souboru nemusí být "extern", ve všech ostatních musí toto klíčové slovo být.

  • Je přímo nastavena pro globální proměnné
  • Sdílená proměnná
  • Nealokuje se, ale moduly používají stejnou proměnnou

Register

Proměnná uložena pouze v registru CPU (jen jestli je volný), velmi rychlá, nedá se přesně určit, kde se uloží. Výhradně jako lokální proměnná.

  • Proměnná bude uložena registru procesoru, pokud je volný, jinak bude zapsána do paměti
  • Pouze pro lokální proměnné
  • Používá se pro rychlejší přístup k proměnné, ale adresu této proměnné nemůžeme získat (není uložena v paměti)
  • Používá se pro proměnné cyklu, nebo pro často volané formální parametry

Zdrojové a hlavičkové soubory v C a C++

06-Hlavičkové

Stavba programu

Struktura programu:

  • Hlavička
  • Příkazy preprocesoru: #include<stdio.h>
  • Pojmenovaná konstanta: #define N 10
  • Deklarace globálních proměnných: int a, b;
  • Definice globálních proměnných: int x=50;
  • Deklarace funkcí: int secti(int a, int b);
  • Hlavní funkce: void main(void)
  • Hlavní program: {
  • Definice lokálních proměnných: int a;
  • Tělo programu
  • Konec hlavního programu: }
  • Definice funkce: int secti (int a, int b)

Vlastní hlavičkový soubor

Vlastní knihovna musí být ve stejném adresáři jako program.

funkce.h

void funkce(void);

funkce.c

void funkce(void) 
 {
  /* ... */
 }

main.c

#include "funkce.h"
int main(void) 
{
  funkce();
  return 0;
}

Souboru main.c v našem příkladu neodpovídá žádný main.h, neboť v main.c neposkytujeme žádné funkce ani proměnné k použití z jiných souborů.

Obvyklá stavba při tvorbě tříd

Když tvořím třídu, deklaraci píšu do souboru s příponou h, do cpp píšu definici (metody).

class Trida
{
private:       // zde vidi jen objekty tridy
int i;    
protected:     // zde vidi jen objekty teto a zdedenych trid
float f:
public: 
Trida();       // implicitni konstruktor
~Trida(); //destruktor
void nacti();  // deklarace fce - definice radeji na konci programu
};

Podmíněný překlad

Direktivy preprocesoru umožňují předepsat, že v závislosti na určitých podmínkách chceme či nechceme překládat určité úseky zdrojového textu.
V následujícím syntaktickém popisu označuje úsek-programu několik řádků Každá direktiva musí být stejně jako ostatní direktivy preprocesoru na samostatném řádku.

Syntaxe:

#if konstantní_výraz nový_řádek 
#ifdef identifikátor nový_řádek 
#ifndef identifikátor nový_řádek 
#elif konstantní_výraz nový_řádek 
#else nový_řádek 
#endif nový_řádek

Podmíněně překládaný úsek programu začíná direktivou #if (nebo #ifdef nebo #ifndef, které slouží jako zkratky pro #if s určitým podmíněným výrazem). Pak může následovat několik úseků začínajících direktivou #elif. Po nich může přijít jeden úsek začínající direktivou #else. Úsek programu s podmíněnou kompilací musí končit direktivou #endif.

Konstantní výrazy mohou obsahovat celočíselné literály, identifikátory definované v direktivě #define a případně operátor defined. V C++ mohou obsahovat i konstanty deklarované pomocí modifikátoru const a inicializované konstantním výrazem.

#if konstantní_výraz_l
  úsek_programu_l 
#elif konstantní_výraz_2 
  úsek_programu_2 
#else usek_programu_3
#endif

Preprocesor vyhodnotí konstantní_výraz_1. Je-li jeho hodnota true (nenulová), přeloží úsek_programu_1. Úseky programu za direktivami #elif a #else ze zdrojového textu vypustí a přejde na zdrojový text za direktivu #endif. Je-li hodnota konstantního_výrazu_1 rovna false, resp. 0, odstraní preprocesor úsek_programu_1 a vyhodnotí konstantní_výraz_2 za #elif. Je-li jeho hodnota nenulová, přeloží úsek_programu_2, odstraní úsek_programu_3 pak přejde za direktivu #endif. Je-li i hodnota konstantního_výrazu_2 rovna false, odstraní se ze zdrojového textu také úsek_programu_2 přeloží úsek_programu_3.

  • Libovolný z úseků programu může opět obsahovat direktivy #if , #endif. Přitom ovšem musíme dát pozor na správné párování #if a #endif.
  • Preprocesor odstraní kromě nepřekládaného zdrojového textu samozřejmě také tyto direktivy.

Projekty

07-Projekty

Práce s více moduly

Vkládání souboru:

Můžu vkládat všechny soubory, nejen hlavičkové, proprocesor tam vloží všechno (#include "b.c"), vyleze z toho jeden OBJ soubor (zpracuje kompiler), při překladu kompiluje oba dva soubory. Tento postup je nevhodný ve velkých týmech, kdy se při malé změně, kompiluje vše znovu.

Odděleným překlad

Více samostatných souborů 'a.c' a 'b.c' musím dát do projektu (záleží na vývojovém prostředí). Musím vložit hlavičkový soubor #include "a.h", musím tam mít podmíněný překlad a deklarace funkcí, konstant, makrer, datových typů, globálních proměnných. V tomto kroku se dva OBJ soubory se spojují do jednoho EXE: a.obj, b.obj.
Výhoda: při malé změně kódu se přeloží jenom jeden změněný soubor.

Do projektu vkládám jen soubory s příponou *.c, nebo OBJ, H tam dává preprocesor sám!!!
Pokud částečně bojujeme v týmu, nedám kolegovi *.c, ale poskytnu mu OBJ a H. Zpracování těchto souborů má nastarosti linker.

Když je include to v uvozovkách, tak se hledá soubor v aktuální složce. Při použití < > se soubory hledají tam, kde běžné includy.

V projektech se využívá podmíněný překlad a oddělený překlad. Ve složitějších projektech je vhodné překládat hlavičkové soubory podmíněně. Hlavičkový soubor se může používat ve více souborech, a tím pádem by se vložil několikrát.

#ifndef _muj_h 
  #define _muj_h 
   
  int Maximum(int a, int b, int c); 
  int Minimum(int a, int b, int c); 
#endif

Práce s projekty v C

Nejprve si vytvoříme adresář, do kterého následně uložíme všechny soubory projektu (programu).
V tomto adresáři vytvoříme další podadresáře pro přehlednost v projektu a to tyto:

  • bin – pro uložení výsledného EXE souboru
  • include – pro uložení hlavičkových souborů s příponou h
  • o – adresář pro soubory s příponou o nebo obj
  • src – adresář pro soubory s příponou c


Soubory s *.c uložíme do podadresáře src. Soubory projektu uložíme v adresáři projektu (tam kde vidíme podadresáře).


Velmi vhodné je přejmenovat soubor Unit1.c na main.c, abychom věděli, kde se nachází funkce main() a také pro přehlednost.


Přes menu Projekt – Options (Shift+Ctrl+F11) zobrazíme okno se záložkami pro nastavení specifických vlastností tohoto projektu.


Na kartě „Path and Defines“ připojíme náš podadresář include: Tlačítkem Edit vyvoláme okno Path, tlačítkem "..." nalezneme náš podadresář a tlačítkem Add jej připojíme k projektu.


Dále zatrhneme položku „Specify object search path“ a stejným způsobem jako v předchozím případě připojíme náš podadresář obj.


Na kartě „Output settings“ zatrhneme „Final output directory“ a připojíme náš podadresář bin.


Klik pravou myší na název modulu a zvolit „Rename“. Jméno modulu se změní jak u zdrojového (*.c) tak také u hlavičkového (*.h) souboru.


Do souborů doplníme příslušný obsah dle typu souboru a uložíme do podadresáře „src“ našeho adresáře projektu. Zde budou uloženy oba soubory modulu *.c i *.h .

Struktura, union a výčet v jazyce C

08-Struktura, union a výčet

Struktura

  • struktura je heterogenní datový typ (je složen z libovolného počtu prvků různých datových typů)
  • navenek vystupuje jako jeden objekt

Struktura není nic jiného než soubor proměnných které mají nějakou logickou souvislost a lze je jako celek nějak použít.

1. Struktura není pojmenována, nedá se využít dále v programu, lze používat pouze definované proměnné:

struct {
        int vyska; 
        float vaha;
       } pavel, honza, karel;

2. Struktura je pojmenována, dá se využít dále v programu

struct miry { 
             int vyska;
             float vaha;
            } pavel, honza, karel;
struct miry jan, martin; // definice proměnných
       miry jan, martin; // chyba

3. Definice struktury jako nový datový typ pomocí příkazu typedef, k definici proměnných není potřeba klíčové slovo struct

typedef struct {
                int vyska;
                float vaha;
               } MIRY;
MIRY pavel, honza, karel;

4. definice pomocí typedef, kdy je struktura pojmenována, používá se, když struktura odkazuje na sebe sama

typedef struct polozka {
                        int hodnota;
                        struct položka *dalsi;
                       } POLOZKA;

Použití

1. Přístup k prvkům pomocí tečkové notace

pavel.vyska = 186;

2. Pole struktur

MIRY lide[100]; 
lide[50].vyska = 176;

3. Je možné pracovat s celou strukturou najednou (honza = pavel – kopie celé struktury najednou)
4. Pole ve struktuře

typedef struct { 
                int pole[10];
               } STR_POLE;
STR_POLE x; 
x.pole[1] = 5;

5. Pointer na strukturu

MIRY *clovek; 
clovek = (MIRY*) malloc(sizeof(MIRY));

6. Přístup k dynamické struktuře

(*clovek).vaha = 70.4; // nebo jednodušeji  
  clovek->vaha = 70.4; 

7. Inicializace struktury

MIRY a = {190, 84.3};

Union

  • Vyhradí se paměť pro největší položku ze všech položek v unionu definovaných
  • Všechny položky unionu se překrývají (ve struktuře by ležely za sebou), tzn. může být v jednom okamžiku použita pouze jedna položka
  • union neposkytuje informaci o prvku, který do něj byl naposledy uložen
typedef union {
               char c;
               int i;
               float f;
              } TEST;

Výčet

= jakási náhrada za symbolické konstanty vytvářené pomocí makra #define. Programátor si pro nový výčtový typ sám definuje množinu přípustných hodnot uvedením všech jejich prvků.
Vnitřně jsou pak tyto konstanty reprezentovány celými čísly, a to nejmenšího znaménkového typu, který je schopen všechny prvky nového typu obsáhnout.

Slouží k definici seznamu symbolických konstant, které jsou většinou vzájemně závislé.

typedef enum {
              MODRA, CERVENA, ZELENA, ZLUTA
             } BARVY;
BARVY x = MODRA;

Čísluje se implicitně od nuly, lze explicitně inicializovat:

typedef enum {
              MODRA = 5, CERVENA = 8, ZELENA, ZLUTA = 15      
             } BARVY;  // ZELENA bude mít číslo 9

Operátory v jazyce C a C++

09-Operátory

Výraz je konstrukce předepisující výpočet hodnoty. Je tvořen operandy a operátory. Operand je proměnná, zápis funkce nebo další výraz. Operátory určují, co provést s hodnotami operandů.


L-hodnota = výraz
L- hodnota
- výraz s výsledkem
- lze do něho výsledek uložit
- má přiřazenou adresu v paměti
- může být vpravo i vlevo

R- hodnota
- vše co není L-hodnota
- může být jen vpravo
- hodnotový výraz – hodnota určitého typu
Příklad (L = l-hodnota, R= r-hodnota):

int a = 0, b = 8;
a = 5 * b; <- R
L -> a = b; <- L
Chyba -> 5 * b = a;

Rozdělení

Operátor určuje operaci, která se má s operandem nebo operandy provést. Mohou být unární (1 operand) nebo binární (2 operandy).

Aritmetické operátory

  • Unární
    • +
    • -
  • Multiplikativní
    • *
    • /
    • %
  • Aditivní
    • +
    • -
  • Relační
    • ==
    • !=
  • Nerovnosti
    • >
    • <
    • <=
    • >=
  • Logické
    • Konjunkce
      • &&
    • Disjunkce
      • ||
  • Inkrementace a dekrementace
    • ++
    • --
  • Přiřazovací
    • +=
    • %= atd.

Unární operátory:

  • Mají zpravidla vyšší prioritu než binární operátory
  • Unární operátory využívají zpravidla prefixový zápis (nejprve operátor, pak operand)
  • Vyjímkou jsou operátory ++ a --, které mají různý význam v prefixovém a postfixovém zápisu

Ternární

Operátor podmíněného výrazu ?:

Syntax:
disjunktivní_výraz ? výraz : podmíněný_výraz

E1 ? E2 : E3

Je-li hodnota E1 rovna true, je výsledkem E2, jinak je výsledkem E3. V případě tohoto operátoru C++ zaručuje, že se jako první vyhodnotí operand El a teprve pak E2 nebo E3 (vždy jen jeden z nich).
Pro typ výsledku platí:

  • Jsou-li oba operandy typu void, je i výsledek téhož typu.
  • Jsou-li oba operandy stejného typu a jsou-li to l-hodnoty, je výsledek téhož typu a je to také l-hodnota.
  • Jinak se operandy převedou pomocí standardních konverzí na stejný typ a to bude i typ výsledku.

Poznámka:
Tento operátor se nepovažuje za jediný symbol, můžeme ho rozdělit bílými znaky.

Priorita operátorů

Dříve se vyhodnocují pochopitelné operátory s vyšší prioritou, pořadí ale můžeme upravit kulatými závorkami. Asociativita určuje, zda se zřetězené operátory vyhodnocují v pořadí zprava doleva nebo zleva doprava.

Zleva doprava:

a + b + c

se vyhodnotí jako

(a + b) + c

Zprava doleva:

a = b = 3.1;

se vyhodnotí jako

a = (b = 3.1);

Proměnné a se přiřadí výsledek operace b = 3.1, tedy hodnota uložená v b.
Pozor: C++ sice předepisuje, v jakém pořadí se vyhodnotí operace, ale nestanoví pořadí, ve kterém se připraví operandy. Jestliže napíšeme

f() + g() + h()

máme sice zaručeno, že se hodnoty, vrácené těmito funkcemi, sečtou v pořadí

(f() + g()) + h()

ale to neznamená, že se funkce f(), g() a h() budou také v tomto pořadí volat. Jestliže to bude překladač pokládat za vhodné (třeba kvůli optimalizaci), může nejprve zavolat funkci g(). výsledek si uložit, pak zavolat třeba h(), výsledek si opět uložit, a nakonec zavolat f (). Tyto dílčí výsledky ovšem musí sečíst v pořadí určeném asociativitou použitých operátorů.

V následující tabulce P znamená prioritu, A asociativitu, je v C říká, zda lze tento operátor používat i v jazyce C, a sloupec l-hodnota říká, zda daný operátor vytváří l-hodnotu.
Operátory, které se skládají z více znaků, nesmíme při zápisu rozdělit, tj. mezi jednotlivé znaky tvořící operátor nesmíme vložit bílé znaky. Výjimkou jsou operátory (), [] a :?.

Přetěžování operátorů

10-Přetěžování

Pravidla

Přetěžování operátorů znamená rozšíření definice některého z existujících operátorů na nový datový typ. Jazyk C++ dovoluje přetížit velkou většinu operátorů. Přetížené operátory budou mít stejnou prioritu i ostatní vlastnosti jako stejnojmenné standardní operátory, budou ale pracovat s novým datovým typem. Přetížený operátor deklarujeme jako volnou („obyčejnou“) funkci nebo jako metodu se jménem tvořeným klíčovým slovem operátor, za kterým následuje symbol operátoru. Jestliže operátor přetížíme jako volnou funkci, musí mít alespoň jeden operand objektového nebo výčtového typu.)

  • Nelze přetížit operátory
    • =
    • ::
    • ?:
    • .
    • *
    • sizeof
    • []
    • #
  • Nelze definovat nové operátory (např. vzít znak @ a definovat jej jako operátor)
  • Nelze měnit obecné charakteristiky operátorů – počet operandů, prioritu, asociativitu.
  • Nelze měnit definici operátorů pro standardní datové typy.
  • Operátorové funkce (mimo new a delete) mohou vracet jakýkoliv datový typ.

Bez tříd

// scitani dvou zlomku(struktur s prvky cit a jmen)
  Zlomek operator+(Zlomek zl1, Zlomek zl2)
  {
    Zlomek soucet;
    soucet.cit=((zl1.cit*zl2.jmen)+(zl1.jmen*zl2.cit));
    soucet.jmen=zl1.jmen*zl2.jmen;
    return soucet;
  }
  

Ve třídách

Komplexní čísla: Upravená deklarace třídy complex tedy může vypadat takto:

// Soubor COMPLEX.H 
 class complex 
  {
   public:
    complex(double r = 0, double i = 0);   //Konstruktor
    complex operator+(complex& c);         //Aritmetické operátory
    complex operator*(complex& c); 
    complex operátor-(complex& c); 
    complex operator/(complex& c); 
    
    double Re();                           //Reálná a imaginární část
    double Im(); 
    double abs();                          //Absolutní hodnota
   private: double re, im;                 //Datové složky
  };

Možná vám připadá podivné, že binární operátory +, - a další zde mají jen jeden parametr.
To je v pořádku: Zápis a+b, kde a a b jsou instance typu complex, bude překladač interpretovat jako volání metody a.operator+(b); a podobné je to i v ostatních případech.