Programovanie (1) v C/C++
1-INF-127, ZS 2017/18

Úvod · Pravidlá · Prednášky · Netbeans · SVGdraw · Testovač
· Vyučujúcich môžete kontaktovať pomocou e-mailovej adresy E-prg.png (bude odpovedať ten z nás, kto má príslušnú otázku na starosti alebo kto má práve čas).
· Druhá opravná písomka bude v utorok 21.11. o 16:30 (po cvičeniach). Prihlasujte sa cez AIS do štvrtka 16.11.
· DÚ3 je zverejnená, odovzdávajte do pondelka 20.11. 22:00.
· Prosíme študentov, aby si pravidelne čítali e-maily na @uniba.sk adrese alebo aby si tieto emaily presmerovali na adresu, ktorú pravidelne čítajú, viď návod tu: [1]


Prednáška 2

Z Programovanie
Prejsť na: navigácia, hľadanie

Opakovanie: Textový výpis a načítanie

Nasledujúci program od užívateľa vypýta dve čísla a vypíše ich súčet.

#include <iostream>
using namespace std;

int main(void) {
    int x, y;

    cout << "Please enter the first number: ";
    cin >> x;
    cout << "Please enter the second number: ";
    cin >> y;

    int result = x + y;
    cout << x << "+" << y << "=" << result << endl;
}
  • Pozor, cin nekontroluje, že užívateľ zadáva rozumné hodnoty. Čo sa stane, ak namiesto čísla zadá nejaké písmená a podobne?
  • Ak pomocou cin načítavame čísla, príkaz preskočí ľubovoľné medzery a konce riadkov

Číslené hodnoty typu int a double

  • Pre začiatok budeme pracovať s premennými typu int a double.
  • Premenná typu int reprezentuje celé číslo.
  • Premenná typu double reprezentuje reálne číslo.
  • Ich rozsah je však obmedzený.
    • Typ int väčšinou zaberá 4 bajty (32 bitov) pamäte a vie ukladať čísla z intervalu <-2 147 483 648, +2 147 483 647>
    • Typ double väčšinou zaberá 8 bajtov a je uložený vo formáte s pohyblivou rádovou čiarkou, t.j. vo forme z\cdot a\cdot 2^{b}, kde z je znamienko, a je reálne číslo z intervalu <1,2) (mantisa) a b je celé číslo (exponent). Na uloženie mantisy sa používa 52 bitov a na uloženie exponentu 11 bitov. Vieme teda spracovávať zhruba čísla v rozsahu od 10^{{-300}} po 10^{{300}} s presnosťou na 15 až 16 platných cifier.
  • Keď priradíme hodnotu typu double do hodnoty typu int, dôjde k jej zaokrúhleniu (nadol pri kladných číslach, nahor pri záporných).

V programe vieme použiť aj konštanty (konkrétne číselné hodnoty):

  • Celočíselné konštanty, ako napríklad 0, 1, 100, -5, majú typ int
  • Konštanty s desatinnou bodkou, ako napríklad 1.5, 1.0, 3.13, -0.5 majú typ double. Môžeme tiež používať semilogaritmický zápis typu 1.5e3, čo znamená 1.5\cdot 10^{3}, t.j. 1500.

Cvičenie: Ako treba zmeniť program na sčítanie dvoch čísel tak, aby pracoval s reálnymi číslami (t.j. napr. po zadaní 1.5 a 1.2 vypíše 2.7)?

Aritmetické výrazy

  • +, -, * (násobenie), / (delenie)
    • delenie celočíselných premenných vráti dolnú celú časť podielu, napr. 5/3 je 1 (pre záporné čísla to môže byť horná celá časť)
  •  % je modulo, napr. 5%3 bude 2, lebo 5 má zvyšok 2 po delení 3
  • ďalšie matematické funkcie vyžadujú #include <cmath> v hlavičke programu
    • napríklad cos(x), sin(x), tan(x) (tangens), acos(x) (arkus kosínus), exp(x) (e^{x}), log(x) (prirodzený logaritmus), pow(x,y) (x^{y}), sqrt(x) (odmocnina), abs(x) (absolútna hodnota), floor(x) (dolná celá časť)
    • pozri tiež zoznam tu

Skratky: Ak chceme zvýšiť hodnotu premennej x o 1, môžeme použiť niektorý z nasledujúcich spôsobov:

  • x = x+1;
  • x++;
  • x += 1;

Podobne ako ++ existuje aj --, podobne ako += existuje aj -=, *= atď

  • Pozor, pri delení celých čísel je výsledkom celé číslo (dolná celá časť podielu)
    • Ak je čitateľ alebo menovateľ typu double, výsledok je typu double
int i=3; int j=2; double d=2;
cout << i / j << endl;  // celočíselné delenie 3/2
cout << i / d << endl;  // neceločíselné delenie 3/2 
   
double c = i / j;
cout << c << endl;      // c je síce desatinné číslo ale bolo do neho priradené celé číslo
cout << c / 3 << endl;  // ale ďalej s ním pracujeme ako s desatinným
   
double b = (1.0 * i) / j; //toto delenie už nie je celočíselné
cout << b << endl;   

double a = ((double)i) / j; //tiež neceločíselné delenie
cout << a << endl;   

Cvičenie: Napíšte program, ktorý načíta reálne čísla a,b,c a vypíše korene kvadratickej rovnice ax2+bx+c=0, pričom predpokladajme, že rovnica má reálne korene.

Podmienka (if)

Niekedy chceme vykonať určité príkazy len ak sú splnené nejaké podmienky. To nám umožňuje príkaz podmienky if.

  • Nasledujúci program si vypýta od užívateľa číslo a vypíše, či je toto číslo párne (even) alebo nepárne (odd).
 #include <iostream>
using namespace std;

int main(void) {
    int x;
    cout << "Please enter some number: ";
    cin >> x;

    if (x % 2 == 0) {
        cout << "Number " << x << " is even." << endl;
    } else {
        cout << "Number " << x << " is odd." << endl;
    }

}
  • Tu je príklad dvoch behov programu:
Please enter some number: 10
Number 10 is even.
Please enter some number: 3
Number 3 is odd.
  • Ako vidíme, za príkazom if je zátvorka s podmienkou. V našom príklade podmienka je x % 2 == 0. Zoberieme teda hodnotu x, pomocou operátora % zistíme zvyšok po delení 0 a pomocou dvoch rovnítok == testujeme, či je tento zvyšok rovný nule.
  • Ak je podmienka v zátvorke splnená (t.j. ak je zvyšok rovný nule), vykonáme príkazy v zloženej zátvorke za príkazom if.
  • Ak podmienka nie je splnená (t.j. ak zvyšok nie je rovný nule), vykonáme príkazy v zloženej zátvorke za slovom else
  • Časť else {...} je možné vynechať, ak nechceme vykonávať žiadne príkazy.
  • Ak za if alebo else nasleduje iba jeden príkaz, zátvorky { a } môžeme vynechať. To však ľahko vedie k chybám, preto je lepšie ich vždy použiť.

Logické konštanty a výrazy

  • Logické konštanty: true (1) a false (0)
  • Logické výrazy dávajú ako výsledok pravdivostnú hodnotu -- logickú konštantu
    • == (rovnosť), != (nerovnosť), <, <=, >, >=
    • && (logický AND), || (logický OR), ! (logický NOT)

Vyhodnocovanie výrazov

Výrazy sa vyhodnocujú s preferenciou podľa nasledovnej tabuľky. Výrazy v jednom riadku tabuľky majú rovnakú prednosť a vyhodnocujú sa väčšinou zľava doprava, okrem !,++,-- a priradenia.

  • ++, --, logický NOT
  • *, /, %
  • +, -
  • <, >, <=, >=
  • ==, !=
  • && (logický AND)
  • || (logický OR)
  • priradenie

Poradie vyhodnocovania môžeme meniť zátvorkami, napr. 4*(5-3)

Viac o operátoroch v C++ nájdete napríklad tu.

Vnorené podmienky

Príkazy if môžeme navzájom vnárať. Príklad: načítaj číslo a zisti, či je kladné, záporné alebo nula.

#include <iostream>
using namespace std;

int main(void) {
    int x;
    cout << "Please enter some number: ";
    cin >> x;

    if (x == 0) {
        cout << "Null" << endl;
    } else {
        if (x > 0) {
            cout << "Positive" << endl;
        } else {
            cout << "Negative" << endl;
        }
    }

}

Upozornenie

Častá chyba, ktorá sa vyskytuje pri podmienke je použitie priradenia namiesto porovnania. Keby sme napísali

if (x=0) cout << “Null” << endl; 

tak program do premennej x priradí nulu, ktorá sa premení na logické false pre účely vyhodnotenia podmienky.

Ďalšia bežná chyba je zabudnutie zložených zátvoriek

   if (x==0) cout << “Null”; cout << endl;

Tento program vykoná cout << endl vždy, nezávisle od podmienky. V prípade, že chceme vykonať v podmienke viacero príkazov, nesmieme zabudnúť ich uzátvorkovať:

   if (x==0) { cout << “Null”; cout << endl; }

Cvičenia

  • V programe na hľadanie koreňov doplňte, aby užívateľa upozornil, keď rovnica nemá reálny koreň. Takisto zvlášť vypíšte prípad keď rovnica má jeden koreň a keď má dva korene.
  • Napíšte program, ktorý načíta čísla a,b,c a vypíše, či sú usporiadané vzostupne, t.j. či platí a<b<c
    • Pozor, výraz a<b<c treba rozpísať na dve porovnania spojené logickou spojkou
  • Nasledujúce dva úryvky programu robia to isté, pričom prvý používa logický operátor && (and) a druhý používa dva príkazy if:
//Verzia 1:
if(x>0 && y>0) { cout << "Yes!"; }

//Verzia 2:
if(x>0) {
  if(y>0) { cout << "Yes!"; }
}
  • Podobne nahraďte logické operátory && a || aj v nasledujúcich príkazoch:
if(x>0 || y>0) { cout << "Yes!"; }
if(x>0 || (x<0 && y<0)) { cout << "Yes!"; }
if(x<0 && (y<0 || z<0)) { cout << "Yes!"; }
  • Nech x je nejaká logická hodnota. Čomu sa rovnajú nasledovné výrazy?
x && true 
x && false 
x || true 
x || false
x && x
x || x 
x && !x
x || !x
x == true 
x == false

Ako by ste si overili, že máte výsledok tohto cvičenia správne?

Cyklus (for)

Teraz si ukážeme príkaz for, ktorý nám umožňuje opakovať viackrát nejakú skupinu príkazov.

Na úvod trochu motivácie. Ako by ste napísali program, ktorý vypíše čísla od 0 po 9? Čo ak chceme vypísať čísla až po 99?

Vypisovanie čísiel

Nasledujúci program vypíše čísla 0 až 9 oddelené medzerami bez toho, aby sme ich niekde v programe explicitne vymenovali.

#include <iostream>
using namespace std;

int main(void) {
    for (int i = 0; i < 10; i++) {
        cout << " " << i;
    }
    cout << endl;
}

Tu je výstup programu.

0 1 2 3 4 5 6 7 8 9

Ak by sme v programe číslo 10 zmenili napr. na 25, vypíše čísla 0 do 24.

  • Novou črtou tohto programu je príkaz for pre cyklus: for (int i = 0; i < 10; i++)
  • Cyklus nám umožňuje opakovať určitú časť programu viackrát.
  • V zátvorke za for sú tri časti oddelené bodkočiarkami.
    • Príkaz int i = 0 vytvorí novú celočíselnú premennú i a priradí jej hodnotu 0.
    • Podmienka i < 10 určuje dokedy sa má cyklus opakovať, t.j. kým hodnota i je menšia ako 10.
    • Príkaz i++ hovorí, že v každom kroku sa má premenná i zvýšiť o jedna.
  • Medzi zložené zátvorky { a } môžeme dať jeden alebo viac príkazov, ktoré sa budú opakovať pre rôzne hodnoty premennej i.
    • V našom príklade máme vo vnútri cyklu iba príkaz cout << " " << i;, ktorý vypíše medzeru a hodnotu premennej i.
  • Po skončení cyklu sa pokračuje príkazmi za končiacou zloženou zátvorkou, v našom prípade vypíšeme ešte koniec riadku.
  • Všimnite si, že náš program obsahuje dve sady zložených zátvoriek vnorených v sebe: jedna ohraničuje celý program, jedna ohraničuje príkazy, ktorá sa robia vo vnútri cyklu.
  • O presnom fungovaní príkazu for si povieme viac neskôr, ale teraz sa pozrime, čo spraví jednoduchá zmena v tomto príkaze:
for (int i = 1; i <= 10; i++) {
  • Počiatočnú príkaz sme zmenili z int i = 0 na int i = 1, premenná i teda začne s hodnotou 1, nie 0. Cyklus môže začať od ľubovoľnej hodnoty (napríklad aj zápornej)
  • Podmienku ukončenia sme zmenili z i < 10 na i <= 10, t.j. cyklus sa opakuje kým je hodnota premennej i menšia alebo rovná 10 (to isté by sme dosiahli aj pomocou i < 11)
  • Program teda vypíše čísla od 1 po 10:
 1 2 3 4 5 6 7 8 9 10

Simulovanie hodov kocky

Nasledujúci program od užívateľa načíta číslo n a vypíše n simulovaných hodov kocky, pred každý dá medzeru.

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main(void) {
    /* inicializácia generátora pseudonáhodných čísel */
    srand(time(NULL));

    int n;
    cout << "Zadajte pocet hodov: ";
    cin >> n;

    for (int i = 0; i < n; i++) {
        int hod = rand() % 6 + 1; // vygenerovanie náhodného hodu
        cout << " " << hod;
    }
    cout << endl;
}

Príklad behu programu:

Zadajte pocet hodov: 10
 1 4 3 2 6 1 6 1 1 5
  • Program využíva príkaz rand(), ktorý generuje pseudonáhodné celé čísla. (Nie sú v skutočnosti náhodné, lebo ide o pevne definovanú matematickú postupnosť, ktorá však má mnohé vlastnosti náhodných čísel).
    • Výsledkom rand() je celé nezáporné číslo medzi 0 a nejakou veľkou konštantou.
    • rand() % 6 je číslo medzi 0 a 5. Ak k tomu pripočítame 1, dostaneme číslo od 1 po 6
  • Príkaz srand inicializuje generátor pseudonáhodných čísel na určitú hodnotu, my použijeme aktuálny čas.
  • Potrebujeme knižnice cstdlib a ctime.

Výpočet faktoriálu

Tento program si od užívateľa vypýta číslo n a spočíta n!, t.j. súčin celých čísel od 1 po n.

#include <iostream>
using namespace std;

int main(void) {
    int n;

    cout << "Please enter n: ";
    cin >> n;

    int result = 1;
    for (int i = 1; i <= n; i++) {
        result = result * i;
    }
    cout << n << "!=" << result << endl;
}

Tu je príklad behu programu pre n=4 (1*2*3*4=24)

Please enter n: 4
4!=24
  • Program používa premennú result, v ktorej sa ukladá dočasný výsledok. Na začiatok ju nastavíme na 1 a postupne ju násobíme číslami 1, 2, ..., n.
  • Riadok result = result * i; zoberie pôvodnú hodnotu premennej result, vynásobí ju hodnotou premennej i (t.j. jedným z čísel 1, 2, ..., n) a výsledok uloží naspäť do premennej result (prepíše pôvodnú hodnotu). To isté sa dá napísať ako result *= i;

Cvičenie: Do programu na vypisovanie hodov kocky doprogramujte, aby program vypísal aj ich súčet.

Organizačné poznámky

  • Do piatka sa v prípade záujmu e-mailom prihláste na test pre pokročilých
  • Budúci pondelok 14:00 test pre pokročilých
  • Budúci týždeň bežný rozvrh, vrátane oboch prednášok a oboch cvičení.
  • Doplnkové cvičenia budúci pondelok:
    • Ak si neviete C++ nainštalovať na notebook, prineste si ho, skúsime pomôcť (hlavne ak máte Windows)
    • Mimoriadne už budú zverejnené niektoré príklady z utorkového cvičenia, začiatočníkom odporúčame prísť a začať ich riešiť