Programovanie (1) v C/C++
1-INF-127, ZS 2024/25
Prednáška 2
Obsah
Oznamy
Opakovanie ako fungujú cvičenia:
- Na začiatku cvičení v utorok sa na testovači objaví nová sada úloh
- Prvá úloha je rozcvička, treba ju odovzdať do konca cvičenia, začnite teda touto úlohou
- Zvyšok cvičenia riešte ďalšie úlohy
- Čo nestihnete na cvičení, môžete dokončiť doma alebo na doplnkových cvičeniach v piatok, termín odovzdania je začiatok cvičenia ďalší utorok
- Úlohy sa dajú odovzdávať aj po termíne, ale nedostanete za ne body, ak sme vám neudelili výnimku
- V piatok príďte na cvičenia, ak vám zostalo veľa príkladov z utorka alebo sa vám zdajú ťažké, takže sa vám zíde pomoc. Tiež ak máte otázky k učivu všeobecne.
- Obvykle nebudú cvičenia predbiehať prednášky, výnimka bola tento týždeň (príklady 4-6)
- Ak vám testovač k príkladu vypíše zelené OK, prešiel testami. Ak vypíše oranžový kód chyby, niečo je zle, treba opraviť a odovzdať znovu.
- Body za prvé cvičenia sa objavia na testovači koncom budúceho týždňa, ale zväčša dostanete body za všetky príklady, kde testovač dal OK.
Cvičenia cez MS Teams
- Ak by ste sa zo zdravotných dôvodov nemohli zúčastniť cvičení osobne, môžete sa zúčastniť online cez MS Teams, návod tu
- Zatiaľ plánujeme cvičenia cez MS Teams sprístupniť tento piatok a budúci utorok, o ďalšom postupe vás budeme informovať
Najbližšie dni na programovaní
- Dnes prednáška, ďalšie dve prednášky budúci týždeň
- Dnes nepovinný test pre pokročilých (ak ste sa prihlásili)
- Doplnkové cvičenia v piatok
- Budúci utorok ďalšie cvičenia s ďalšou sadou úloh (k prednáške dnes a v pondelok)
- Niektorí ste vyriešili všetky príklady na tento týždeň, pokúsime sa do piatku zverejniť aj pár úloh z budúceho týždňa, aby ste tí, čo ste pokročilejší, si ich mohli spraviť vopred. Neskôr už ale toto robiť nebudeme pre organizačnú náročnosť. Rozcvička na budúci týždeň sa objaví až na cvičeniach
Technické záležitosti
- Na stránke Softvér nájdete príklady ďalších programov, ktoré môžete použiť namiesto Kate.
- Ak sa vám páči Kate, prečítajte si časť o Kate a práci na príkazovom riadku. Vo Windows si môžete nainštalovať podobný editor, napr. Notepad++.
- Ak by ste chceli viac klikacie prostredie, môžete skúsiť napríklad program Netbeans, dá sa použiť aj na skúške a možno ho budeme používať budúci semester. Mal by sa dať nainštalovať aj vo Windows.
- Na svojom počítači máte širokú paletu možností, v čom programovať, aspoň občas ale skúste použiť Linux na cvičeniach, aby ste vedeli robiť skúšku (Kate alebo Netbeans alebo iné nástroje, nie však internetové prostredia).
Ďalšie upozornenia k štúdiu:
- V rozvrhu http://candle.fmph.uniba.sk/ vidíte všetky predmety, ktoré sú povinné, povinne voliteľné alebo výberové pre váš ročník, ale nie všetky si musíte zapísať a naopak, môžete si zapísať aj iné predmety
- Dôležité je skontrolovať si, či to máte zapísané v AIS, sedí s tám, na čo aj reálne chodíte
- Prvé dva týždne (do 4.10.) si môžete v AIS pridávať a uberať predmety, potom treba kontaktovať študijné emailom, aby vám uzatvorili zápisný list
- Prvácke povinné a povinne voliteľné predmety by ste si mali zapísať, z výberových si môžete vybrať
- Pozor na to, aby ste získali aspoň 20 kreditov za zimný semester.
- Z angličtiny je povinná Angličtina 4 v letnom semestri (väčšinou prvý alebo druhý ročník), ostatné sú výberové s cieľom pripraviť sa na Angličtinu 4.
- Bioinformatikom pripomíname možnosť prestupu na konverzné štúdium, ak by sa vám učilo v prých týždňoch zdalo príliš ťažké.
Opakovanie
Doteraz sme videli:
- Načítavanie pomocou cin, výpis pomocou cout.
- Celočíselné premenné typu int.
#include <iostream>
using namespace std;
int main() {
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;
}
Komentáre
Do zdrojových kódov programov v jazykoch C a C++ je možné pridávať komentáre, čo sú časti kódu ignorované kompilátorom.
- Komentár je časť programu začínajúca /* a končiaca */ (aj cez viac riadkov)
- Komentár je aj text od // až po koniec riadku. To je užitočné na písanie krátkych komentárov.
Do komentárov sa zvyknú písať poznámky k významu okolitých príkazov, čo zlepšuje orientáciu v kóde a jeho pochopenie inými programátormi.
Príklad:
#include <iostream>
using namespace std;
/* Tento program od pouzivatela nacita dve cele cisla
* a vypise ich sucet. */
int main() {
// vytvorime premenne x a y
int x, y;
// do premennych od pouzivatela nacitame cisla
cout << "Please enter the first number: ";
cin >> x;
cout << "Please enter the second number: ";
cin >> y;
// do novej premennej result spocitame vysledok
int result = x + y;
// vysledok vypiseme
cout << x << "+" << y << "=" << result << endl;
}
Podmienka (if)
Niekedy chceme vykonať určité príkazy len ak sú splnené nejaké podmienky. To nám umožňuje príkaz if.
- Nasledujúci program si vypýta od používateľa číslo a vypíše, či je toto číslo záporné alebo nezáporné.
#include <iostream>
using namespace std;
int main(void) {
int x;
cout << "Zadajte cislo: ";
cin >> x;
if (x < 0) {
cout << "Cislo " << x << " je zaporne." << endl;
} else {
cout << "Cislo " << x << " je nezaporne." << endl;
}
}
- Tu je príklad dvoch behov programu:
Zadajte cislo: 10 Cislo 10 je nezaporne.
Zadajte cislo: -3 Cislo -3 je zaporne.
- Ako vidíme, za príkazom if je zátvorka s podmienkou. V našom príklade podmienka je x < 0.
- Ak je podmienka v zátvorke splnená (t.j. ak x je menšie ako nula), vykonáme príkazy v zloženej zátvorke za príkazom if.
- Ak podmienka nie je splnená (t.j. ak je x väčšie alebo 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ť.
Cvičenie:
- Pomocou podmienky vypíšte absolútnu hodnotu načítaného čísla.
- Namiesto vypísania uložte túto hodnotu do premennej y, ktorá by sa dala ďalej v programe použiť.
Dátové typy int, double a bool
Na začiatok budeme pracovať s troma dátovými typmi:
- typ int pre celé čísla – príkladmi konštánt typu int sú 1, 42, -2, alebo 0.
- typ double pre reálne čísla – príkladmi konštánt typu double sú 4.2, -3.0, 3.14159, alebo 1.5e3 (1.5e3 je tzv. semilogaritmický zápis znamenajúci 1,5 ⋅ 103, t.j. 1500).
- typ bool pre logické hodnoty – jedinými konštantami sú true (ekvivalentná číselnej hodnote 1) a false (ekvivalentná číselnej hodnote 0).
Premenné typu int a double zaberajú pevne daný počet bitov, preto do nich nie je možné uložiť ľubovoľné celé alebo reálne číslo. Presný rozsah možných hodnôt môže závisieť od kompilátora, v súčasnosti však väčšinou platí:
- Typ int zvyčajne zaberá 4 bajty (32 bitov) a dajú sa ním reprezentovať celé čísla z intervalu <-2 147 483 648, +2 147 483 647>.
- Typ double zvyčajne zaberá 8 bajtov. Ním reprezentované reálne čísla sú v pamäti uložené vo forme z ⋅ a ⋅ 2b, 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. Typ double tak možno použiť na prácu s reálnymi číslami približne v rozsahu od 10-300 po 10^{300} s presnosťou na 15 až 16 platných číslic. Pri tejto reprezentácii sa nevyhradzujú pevné počty bitov na reprezentáciu celej a desatinnej časti; počet cifier pred a za rádovou čiarkou je určený exponentom. Hovoríme preto o pohyblivej rádovej čiarke.
Pretypovanie
Hodnotu niektorého z typov bool, int, double je možné skonvertovať na „zodpovedajúcu” hodnotu ľubovoľného ďalšieho z týchto typov. V takom prípade hovoríme o pretypovaní. Platí pritom nasledujúce:
- Konverzia z „menej všeobecného” typu na „všeobecnejší” sa správa očakávateľným spôsobom. Booleovské hodnoty false resp. true sa konvertujú na celé čísla 0 resp. 1, prípadne na reálne čísla 0.0 resp, 1.0; celé číslo sa tiež konvertuje na reálne číslo, ktoré je mu rovné.
- Konverzia zo „všeobecnejšieho” typu na „menej všeobecný” dodržiava určité vopred stanovené pravidlá. Napríklad pri konverzii z int alebo double na bool sa ľubovoľná nenulová hodnota skonvertuje na true a nula sa skonvertuje na false. Pri konverzii z double na int dôjde k zaokrúhleniu smerom k nule (čiže nadol pri kladných číslach, nahor pri záporných).
Pretypovanie je možné realizovať dvoma spôsobmi:
- Implicitne, napríklad priradením premennej jedného typu do premennej iného typu, alebo použitím premennej jedného typu v kontexte, kde sa očakáva premenná druhého typu.
- Explicitne, použitím pretypovacieho operátora: (nazov_noveho_typu) vyraz_stareho_typu.
Možnosti pretypovania sú ilustrované nasledujúcim ukážkovým programom.
#include <iostream>
using namespace std;
int main() {
bool b1 = true;
int n1 = 4;
double x1 = 1.234;
bool b2;
int n2;
b2 = n1; // b2 = 1
n2 = x1; // n2 = 1
cout << b2 << " " << n2 << endl; // Vypise 1 1
x1 = n2; // x1 = 1.0
cout << x1 << endl; // Vypise 1
cout << (bool) 7 << " " << (bool) 0 << endl; // Vypise 1 0
cout << (int) 4.2 << " " << (int) -4.2 << endl; // Vypise 4 -4
}
Aritmetické operátory a výrazy
Na typoch int aj double sa dajú robiť základné aritmetické operácie
- sčítanie +
- odčítanie -
- násobenie *
- delenie /
Operátor / sa na argumentoch typu int správa ako celočíselné delenie – hodnota podielu sa zaokrúhli smerom k nule.
- Napríklad výraz 5/3 má hodnotu 1.
- Akonáhle je však aspoň jeden operand typu double, interpretuje sa / ako delenie reálnych čísel.
- Výrazy 5.0/3.0, 5.0/3, 5/3.0 a 5/(double)3 teda majú všetky hodnotu 1.66667.
#include <iostream>
using namespace std;
int main() {
int a = 4;
int b = 3;
// Automaticky pretypuje cele cislo 3 na realne cislo 3.0
double d = 3;
// Celociselne delenie: 4 / 3 = 1
cout << a / b << endl;
// Necelociselne delenie: 4 / 3.0 = 1.33333
cout << a / d << endl;
// Necelociselne delenie: (1.0 * 4) / 3 = 4.0 / 3 = 1.33333
cout << (1.0 * a) / b << endl;
// Necelociselne delenie: 3.0 / 4 = 1.33333
cout << ((double)a) / b << endl;
// Do e je priradeny vysledok celociselneho delenia 4 / 3 = 1;
// po pretypovani je to rovne 1.0
double e = a / b;
// Vypise 1
cout << e << endl;
// Vypise 0.5, lebo 1.0 / 2 je necelociselne delenie
cout << e / 2 << endl;
}
- Na celých číslach je definovaný operátor %, ktorého výstupom je zvyšok po celočíselnom delení (modulo). Napríklad výraz 5%3 má hodnotu 2.
- Ďalšie matematické operácie a funkcie vyžadujú #include <cmath> (pre jazyk C++) v hlavičke programu:
- Napríklad cos(x), sin(x), tan(x) (tangens), acos(x) (arkus kosínus), exp(x) (ex), log(x) (prirodzený logaritmus), pow(x,y) (xy), sqrt(x) (odmocnina), abs(x) (absolútna hodnota), floor(x) (dolná celá časť), ...
- Viac detailov možno nájsť v dokumentácii.
Relačné operátory
Hodnoty typov int, double a bool možno porovnávať nasledujúcimi relačnými operátormi:
- == pre rovnosť;
- != pre nerovnosť;
- < pre reláciu „menší ako”;
- > pre reláciu „väčší ako”;
- <= pre reláciu „menší alebo rovný ako”;
- >= pre reláciu „väčší alebo ako”.
Výstupom relačného operátora je logická hodnota true alebo false.
Logické operátory a výrazy
Na výrazoch typu bool sú definované logické operátory, ktoré sa správajú rovnako ako logické spojky známe z výrokovej logiky:
- || pre disjunkciu (or, alebo);
- && pre konjunkciu (and, a súčasne);
- ! pre negáciu (not, opak)
Logickým výrazom je napríklad !((x >= 2) && (x <= 4)) alebo !true.
Operátory priradenia, inkrementu a dekrementu
Operátor priradenia premenna = hodnota už poznáme. Často realizovanou operáciou na číslach je zvýšenie hodnoty o 1. To možno urobiť napríklad nasledujúcimi spôsobmi:
- x=x+1;
- x+=1;
- x++;
Analogicky sú definované operátory ako --, -=, *=, atď.
Priorita a asociativita operátorov
Výrazy sa vyhodnocujú v nasledujúcom poradí preferencie jednotlivých operátorov. Operátory v jednom riadku majú rovnakú prioritu a operátory vo vyššom riadku majú vyššiu prioritu, než operátory v nižších riadkoch.
- ++ (inkrement), -- (dekrement), ! (logická negácia)
- *, /, %
- +, -
- <, >, <=, >=
- ==, !=
- && (logická konjunkcia)
- || (logická disjunkcia)
- = (priradenie)
Poradie vyhodnocovania je možné meniť zátvorkami, ako napríklad vo výraze 4*(5-3).
Uvedené operátory sa väčšinou vyhodnocujú zľava doprava (hovoríme, že sú zľava asociatívne) – napríklad 1 - 2 - 3 sa teda vyhodnotí ako (1 - 2) - 3, t.j. -4 a nie ako 1 - (2 - 3), t.j. 2. Výnimkou sú operátory !, ++, -- a =, ktoré sú sprava asociatívne. To umožňuje napríklad viacnásobné priradenie a = b = c, ktoré najprv priradí hodnotu c do b a následne hodnotu výrazu b = c – tou je nová hodnota premennej b, čiže hodnota premennej c –, do a.
Viac sa o operátoroch v C++ možno dočítať napríklad tu.
Viac o podmienkach
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 << "Zero" << endl;
} else {
if (x > 0) {
cout << "Positive" << endl;
} else {
cout << "Negative" << endl;
}
}
}
Logické výrazy môžu byť efektívnym nástrojom na elimináciu množstva vnorených podmienok: napríklad konštrukcia typu
if (a == 0) {
if (b == 0) {
čokoľvek
}
}
je ekvivalentná konštrukcii
if (a == 0 && b == 0) {
čokoľvek
}
Upozornenie
Častou chybou je použitie priradenia namiesto porovnania. Nasledujúci kúsok programu do premennej x priradí nulu, ktorá sa premení na false pre účely vyhodnotenia podmienky.
if (x=0) cout << “Null” << endl;
Ď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
- 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
Cyklus for
Dôležitou časťou programovania je schopnosť opakovanie vykonávať tie isté príkazy. Prvou možnosťou ako to robiť, je cyklus for.
Príklad 1: vypisovanie čísel od 1 po n
Nasledujúci program načíta zo vstupu číslo n a postupne vypíše prirodzené čísla od 1 po n (pred každé dá medzeru).
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cout << " " << i;
}
cout << endl;
}
Tu je výstup programu pre n = 9:
1 2 3 4 5 6 7 8 9
Cyklus for vyzeral v programe takto:
for (int i = 1; i <= n; i++) {
telo cyklu
}
Táto konštrukcia pozostáva z kľúčového slova for nasledovaným zátvorkou s troma časťami oddelenými bodkočiarkami:
- Príkaz int i = 1 vytvorí novú celočíselnú premennú i a priradí jej hodnotu 1.
- Podmienka i <= n určuje dokedy sa má cyklus opakovať. V tomto prípade to má byť kým je hodnota premennej i menšia alebo rovná n.
- Príkaz i++ hovorí, že po každom zopakovaní cyklu (t.j. po každej jeho iterácii) sa má hodnota premennej i zvýšiť o jedna.
- Medzi zloženými zátvorkami { a } je potom tzv. telo cyklu – čiže jeden alebo viac príkazov, ktoré sa budú opakovať postupne pre rôzne hodnoty premennej i.
V príklade 1 je telom cyklu iba príkaz cout << " " << i;, ktorý vypíše medzeru a hodnotu premennej i.
Príklad 2: vypisovanie čísel od 0 po n-1
Drobnou zmenou predchádzajúceho programu môžeme napríklad vypísať všetky čísla od 0 po n-1:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cout << " " << i;
}
cout << endl;
}
Tu je výstup programu pre n = 9:
0 1 2 3 4 5 6 7 8
Príklad 3: výpočet faktoriálu
Nasledujúci program si od používateľa vypýta číslo n a vypočíta n!, t.j. súčin celých čísel od 1 po n.
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Zadajte n: ";
cin >> n;
int vysledok = 1;
for (int i = 1; i <= n; i++) {
vysledok = vysledok * i;
}
cout << n << "! = " << vysledok << endl;
}
Príklad behu programu pre n=4 (1*2*3*4=24):
Zadajte n: 4 4! = 24
- Program používa premennú vysledok, ktorú na začiatku inicializuje hodnotou 1 a postupne ju násobí číslami 1, 2, ..., n.
- Riadok vysledok = vysledok * i; zoberie pôvodnú hodnotu premennej vysledok, vynásobí ju hodnotou premennej i (t.j. jedným z čísel 1, 2, ..., n) a výsledok uloží naspäť do premennej vysledok (prepíše pôvodnú hodnotu). To isté sa dá napísať ako vysledok *= i;
Funkcia n! však veľmi rýchlo rastie a už pre n=13 sa výsledok nezmestí do premennej typu int. Dostávame nezmyselné hodnoty:
12! = 479001600 13! = 1932053504 14! = 1278945280 15! = 2004310016 16! = 2004189184 17! = -288522240
Správne hodnoty (ktoré možno získať zmenou typu premennej vysledok na long long int) sú:
12! = 479001600 13! = 6227020800 14! = 87178291200 15! = 1307674368000 16! = 20922789888000 17! = 355687428096000
Cvičenie: rozšírte program tak, aby okrem výpisu výsledku aj rozpísal faktoriál ako súčin:
Zadajte n: 4 4! = 1*2*3*4 = 24
Zhrnutie
Poznáme základné stavebné prvky, z ktorých sa dajú spraviť aj pomerne zložité programy:
- premenné typu int, double, bool a operátory, ktoré s nimi vedia počítať
- podmienku if, ktorá umožňuje vykonávať určité časti programu len za nejakých okolností
- cyklus for, ktorý umožnuje opakovať určité časti programu veľa krát
Cieľom najbližšej prednášky a cvičení je hlavne precvičiť si tieto stavebné prvky na veľa ďalších príkladoch.