Programovanie (1) v C/C++
1-INF-127, ZS 2024/25

Úvod · Pravidlá · Prednášky · Softvér · Testovač
· Kontaktujte nás 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).
· Prosíme študentov, aby si pravidelne čítali e-maily na @uniba.sk adrese alebo aby si tieto emaily preposielali na adresu, ktorú pravidelne čítajú.


Prednáška 4b: Rozdiel medzi revíziami

Z Programovanie
Skočit na navigaci Skočit na vyhledávání
 
(21 medziľahlých úprav od 3 ďalších používateľov nie je zobrazených)
Riadok 1: Riadok 1:
 
== Oznamy ==
 
== Oznamy ==
 
Program na dnes:
 
Program na dnes:
* oznamy, návod na dištančnú výučbu
+
* oznamy
 
* teoretické cvičenie (krátky test)
 
* teoretické cvičenie (krátky test)
 
* vzorové riešenia testu
 
* vzorové riešenia testu
Riadok 7: Riadok 7:
  
 
Čo nás čaká v najbližších dňoch
 
Čo nás čaká v najbližších dňoch
* zajtra hlavné cvičenia cez MS Teams, rozcvička na funkcie (pozrite si pred cvičením)
+
* zajtra hlavné cvičenia, rozcvička na funkcie (pozrite si pred cvičením)
 
* v stredu prednáška o poliach
 
* v stredu prednáška o poliach
* v stredu bude zverejnené zadanie prvej domácej úlohy
+
* v piatok doplnkové cvičenia: povinné pre tých, čo v utorok na cvičení nezískajú aspoň 5 bodov
* v piatok doplnkové cvičenia
 
* [[MS Teams|návod na použitie MS Teams]]
 
  
Zmeny v [[Zimný semester, pravidlá|pravidlách predmetu]] súvisiace s dištančnou výučbou
+
Dnešné teoretické cvičenie
* Počet písomiek cez semester sa znížil z 3 na 1, váha písomiek z 30% na 20%
+
* krátky bodovaný testík, počíta sa do cvičení (spolu 4 body, cca 1% známky)
** Dnešné teoretické cvičenia vo forme testu sa počítajú do bodov z cvičení, nie do písomiek
+
* ciele: zopakovať si učivo, rozmýšľať nad hotovými programami bez kompilovania a spúšťania programu, tréning na semestrálny test
* Naopak váha záverečnej skúšky vzrástla z 30% na 40%, môže zahŕňať ústnu skúšku
+
* môžete používať pero a ťahák vo forme jedného obojstranne popísaného listu A4
* Pridala sa podmienka, že v prípade konania ústnej skúšky aj z tejto treba získať aspoň polovicu bodov.
 
  
 
==Opakovanie==
 
==Opakovanie==
Riadok 25: Riadok 22:
  
 
Definícia funkcie pozostáva z nasledujúcich častí:
 
Definícia funkcie pozostáva z nasledujúcich častí:
* Typ návratovej hodnoty funkcie (napríklad <tt>double</tt>, <tt>double</tt>, <tt>void</tt>)
+
* Typ návratovej hodnoty funkcie (napríklad <tt>double</tt>, <tt>int</tt>, <tt>void</tt>)
 
* Identifikátor funkcie (použite výstižný názov)
 
* Identifikátor funkcie (použite výstižný názov)
 
* Zoznam vstupných parametrov funkcie a ich typov
 
* Zoznam vstupných parametrov funkcie a ich typov
Riadok 31: Riadok 28:
 
* Príkaz <tt>return</tt> vracia návratovú hodnotu funkcie a ukončí jej beh
 
* Príkaz <tt>return</tt> vracia návratovú hodnotu funkcie a ukončí jej beh
  
 +
Platnosť lokálnych premenných je obmedzená na funkciu (alebo blok) v ktorej boli zadefinované. Globálne premenné je možné používať vo všetkých funkciách, zvyčajne sa chceme ich použitiu vyhnúť.
  
===Príklad programu s využitím funkcie===
+
==Odovzdávanie parametrov==
 
 
<syntaxhighlight lang="C++">
 
#include <iostream>
 
#include <cmath>
 
using namespace std;
 
 
 
/* Definicia funkcie dist: */
 
double dist(double x1, double y1, double x2, double y2) {
 
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
 
}
 
 
 
int main() {
 
    double Ax, Ay, Bx, By, Cx, Cy;
 
   
 
    cout << "Zadaj suradnice vrcholu A: ";
 
    cin >> Ax >> Ay;
 
    cout << "Zadaj suradnice vrcholu B: ";
 
    cin >> Bx >> By;
 
    cout << "Zadaj suradnice vrcholu C: ";
 
    cin >> Cx >> Cy;
 
   
 
    // Spocitaj dlzky jednotlivych stran:
 
 
 
    // Volanie funkcie dist s argumentmi Bx, By, Cx, Cy
 
    double a = dist(Bx, By, Cx, Cy);
 
    // Volanie funkcie dist s argumentmi Ax, Ay, Cx, Cy
 
    double b = dist(Ax, Ay, Cx, Cy);
 
    // Volanie funkcie dist s argumentmi Ax, Ay, Bx, By
 
    double c = dist(Ax, Ay, Bx, By);
 
   
 
    cout << "Obvod trojuholnika ABC: " << a + b + c;
 
}
 
</syntaxhighlight>
 
 
 
===Lokálne a globálne premenné===
 
 
 
* Globálne premenné sú definované mimo funkcie a možno ich používať vo všetkých funkciách, ktoré sú v programe definované za touto premennou.
 
* Lokálne premenné sú definované vo vnútri funkcie a môžu sa používať iba v rámci nej (alebo iba v rámci niektorej jej časti).
 
* Viaceré funkcie môžu mať lokálne premenné s tým istým názvom, každá funkcia potom používa tú svoju.
 
* Je silno odporúčané ''používať predovšetkým lokálne premenné''. Väčšie programy s globálnymi premennými môžu byť veľmi neprehľadné.
 
 
 
===Odovzdávanie parametrov===
 
 
* Hodnotou: parametre sa nakopírujú, ďalej fungujú ako lokálne premenná funkcie (napr. <tt>double x</tt>)
 
* Hodnotou: parametre sa nakopírujú, ďalej fungujú ako lokálne premenná funkcie (napr. <tt>double x</tt>)
* Referenciou: parameter je nové meno pre premennú z volajúcej funkcie
+
* Referenciou: parameter je nové meno pre premennú z volajúcej funkcie (napr. <tt>double &x</tt>)
  
=== Viac ako jedna návratová hodnota ===
+
=== Odovzdávanie parametrov hodnotou===
 
 
Odovzdávanie parametra referenciou používame napríklad vtedy, keď potrebujeme vrátiť viac ako jednu výstupnú hodnotu.
 
 
 
Napríklad nasledujúca funkcia <tt>mid</tt> dostane súradnice dvoch bodov <tt>[x1,y1]</tt> a <tt>[x2,y2]</tt> a do parametrov <tt>[xm,ym]</tt>, ktoré sú odovzdané referenciou, uloží súradnice stredu úsečky spájajúcej body <tt>[x1,y1]</tt> a <tt>[x2,y2]</tt>.
 
  
 +
Vstupné parametre funkcií sa správajú ako lokálne premenné danej funkcie. Pri volaní funkcie sa každému parametru priradí určitá hodnota. Uvažujme napríklad funkciu
 
<syntaxhighlight lang="C++">
 
<syntaxhighlight lang="C++">
#include <iostream>
+
void f(int a, int b) {
using namespace std;
+
     // ...
 
 
void mid(double x1, double y1, double x2, double y2,
 
        double &xm, double &ym) {
 
     xm = (x1 + x2) / 2;
 
    ym = (y1 + y2) / 2;
 
}
 
 
 
int main() {
 
    double Ax, Ay, Bx, By;
 
   
 
    cout << "Zadaj suradnice bodu A: ";
 
    cin >> Ax >> Ay;
 
    cout << "Zadaj suradnice bodu B: ";
 
    cin >> Bx >> By;
 
   
 
    double Mx, My;
 
    mid(Ax, Ay, Bx, By, Mx, My);
 
    cout << "Stred usecky AB je ["
 
        << Mx << ", " << My << "]." << endl;
 
 
}
 
}
 +
</syntaxhighlight>
 +
Pri volaní
 +
<syntaxhighlight lang="C++">
 +
f(1, 2);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
sa parametru <tt>a</tt> priradí hodnota 1 a parametru <tt>b</tt> sa priradí hodnota 2. Tieto sa ďalej správajú ako lokálne premenné funkcie <tt>f</tt>. Možno ich teda meniť, ale táto zmena sa neprejaví na mieste, odkiaľ funkciu voláme. Tento mechanizmus nazývame ''odovzdávaním parametrov hodnotou''.
  
=== Funkcia <tt>swap</tt> ===
+
Príklad:
 
 
Typickým príkladom použitia odovzdávania parametrov referenciou je funkcia <tt>swap</tt>, ktorá vymení hodnoty dvoch premenných, ktoré dostane ako parametre.
 
 
 
 
<syntaxhighlight lang="C++">
 
<syntaxhighlight lang="C++">
 
#include <iostream>
 
#include <iostream>
 
using namespace std;
 
using namespace std;
  
void swap(int &a, int &b) {
+
void f(int n) {
     int tmp = a;
+
     n++;
    a = b;
+
     cout << n << endl;
     b = tmp;
 
 
}
 
}
  
 
int main() {
 
int main() {
     int x, === Viac ako jedna návratová hodnota ===
+
     int n = 1;
 
+
     f(n);              // Vypise 2
Odovzdávanie parametra referenciou používame napríklad vtedy, keď potrebujeme vrátiť viac ako jednu výstupnú hodnotu.
+
     cout << n << endl; // Vypise 1
 
 
Napríklad nasledujúca funkcia <tt>mid</tt> dostane súradnice dvoch bodov <tt>[x1,y1]</tt> a <tt>[x2,y2]</tt> a do parametrov <tt>[xm,ym]</tt>, ktoré sú odovzdané referenciou, uloží súradnice stredu úsečky spájajúcej body <tt>[x1,y1]</tt> a <tt>[x2,y2]</tt>.
 
 
 
<syntaxhighlight lang="C++">
 
#include <iostream>
 
using namespace std;
 
 
 
void mid(double x1, double y1, double x2, double y2,
 
        double &xm, double &ym) {
 
     xm = (x1 + x2) / 2;
 
    ym = (y1 + y2) / 2;
 
}
 
 
 
int main() {
 
    double Ax, Ay, Bx, By;
 
   
 
     cout << "Zadaj suradnice bodu A: ";
 
    cin >> Ax >> Ay;
 
    cout << "Zadaj suradnice bodu B: ";
 
    cin >> Bx >> By;
 
   
 
    double Mx, My;
 
    mid(Ax, Ay, Bx, By, Mx, My);
 
    cout << "Stred usecky AB je ["
 
        << Mx << ", " << My << "]." << endl;  
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Funkcia <tt>swap</tt> ===
+
=== Odovzdávanie parametrov referenciou===
  
Typickým príkladom použitia odovzdávania parametrov referenciou je funkcia <tt>swap</tt>, ktorá vymení hodnoty dvoch premenných, ktoré dostane ako parametre.
+
V prípade, že pred názov niektorého parametra v hlavičke funkcie napíšeme <tt>&</tt>, parameter sa bude ''odovzdávať referenciou''.
 +
* Za takýto parameter možno pri volaní funkcie dosadiť iba premennú (kým pri odovzdávaní hodnotou môžeme použiť napríklad aj konštanty alebo iný výraz).
 +
* Namiesto hodnoty sa funkcii pošle adresa premennej v pamäti (referencia).
 +
* Funkcia potom bude túto premennú používať pod novým názvom; jej prípadné zmeny sa prejavia aj na mieste, odkiaľ bola funkcia volaná.
  
 +
Príklad:
 
<syntaxhighlight lang="C++">
 
<syntaxhighlight lang="C++">
 
#include <iostream>
 
#include <iostream>
 
using namespace std;
 
using namespace std;
  
void swap(int &a, int &b) {
+
void f(int &n) {
     int tmp = a;
+
     n++;
    a = b;
+
     cout << n << endl;
     b = tmp;
 
 
}
 
}
  
 
int main() {
 
int main() {
     int x, y;
+
     int n = 1;
    cin >> x >> y;
+
     f(n);               // Vypise 2.
      
+
     cout << n << endl; // Vypise 2.
    swap(x, y);
 
   
 
     cout << "x = " << x << ", y = " << y << endl;  
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Keby sme funkcii odovzdali parameter hodnotou &ndash; čiže by sme funkciu <tt>swap</tt> definovali s hlavičkou <tt>void swap(int a, int b);</tt> &ndash; vo funkcii <tt>main</tt> by sa premenné nevymenili.
+
Ďalej si ukážeme niekoľko použití odovzdávania parametrov referenciou.
y;
+
 
    cin >> x >> y;
+
=== Viac ako jedna návratová hodnota ===
   
 
    swap(x,=== Viac ako jedna návratová hodnota ===
 
  
 
Odovzdávanie parametra referenciou používame napríklad vtedy, keď potrebujeme vrátiť viac ako jednu výstupnú hodnotu.
 
Odovzdávanie parametra referenciou používame napríklad vtedy, keď potrebujeme vrátiť viac ako jednu výstupnú hodnotu.
Riadok 233: Riadok 141:
 
      
 
      
 
     swap(x, y);
 
     swap(x, y);
   
 
    cout << "x = " << x << ", y = " << y << endl;
 
}
 
</syntaxhighlight>
 
 
Keby sme funkcii odovzdali parameter hodnotou &ndash; čiže by sme funkciu <tt>swap</tt> definovali s hlavičkou <tt>void swap(int a, int b);</tt> &ndash; vo funkcii <tt>main</tt> by sa premenné nevymenili.
 
y);
 
 
      
 
      
 
     cout << "x = " << x << ", y = " << y << endl;  
 
     cout << "x = " << x << ", y = " << y << endl;  
Riadok 280: Riadok 181:
  
 
Ak však používateľ zadá na vstupe nejaké záporné číslo, funkcia vždy vráti nulu, čo nie je úplne v súlade s očakávaním. Jednou možnosťou by samozrejme bolo prerobiť funkciu tak, aby pracovala správne aj na záporných vstupoch. Sú však aj situácie, keď podobné riešenie nie je možné. Ukážeme si preto ďalšie spôsoby, ako sa s nekorektným vstupom vysporiadať.  
 
Ak však používateľ zadá na vstupe nejaké záporné číslo, funkcia vždy vráti nulu, čo nie je úplne v súlade s očakávaním. Jednou možnosťou by samozrejme bolo prerobiť funkciu tak, aby pracovala správne aj na záporných vstupoch. Sú však aj situácie, keď podobné riešenie nie je možné. Ukážeme si preto ďalšie spôsoby, ako sa s nekorektným vstupom vysporiadať.  
 
=== Použitie funkcie <tt>exit</tt> ===
 
 
V prípade použitia nekorektného vstupu napríklad môžeme celý program ihneď ukončiť funkciou <tt>exit</tt> (treba <tt>#include <cstdlib></tt>).
 
* Parametrom tejto funkcie je návratová hodnota celého programu, ktorá typicky udáva, či program skončil korektne alebo nie.
 
* Na vyjadrenie neúspešného ukončenia programu použijeme preddefinovanú konštantu <tt>EXIT_FAILURE</tt>.
 
 
<syntaxhighlight lang="C++">
 
#include <iostream>
 
#include <cstdlib>
 
using namespace std;
 
 
int sumOfDivisors(int n) {
 
    if (n <= 0) {
 
        exit(EXIT_FAILURE);   
 
    }
 
    int sum = 0;
 
    for (int i = 1; i <= n; i++) {
 
        if (n % i == 0) {
 
            sum += i;   
 
        }       
 
    } 
 
    return sum; 
 
}
 
 
int main() {
 
    int n;
 
    cout << "Zadaj kladne cele cislo: ";
 
    cin >> n;
 
       
 
    cout << "Sucet delitelov " << n << ": "
 
        << sumOfDivisors(n) << "." << endl;
 
}
 
</syntaxhighlight>
 
  
 
=== Použitie funkcie <tt>assert</tt> ===
 
=== Použitie funkcie <tt>assert</tt> ===
  
Pohodlnejšou alternatívou je použitie funkcie <tt>assert</tt> (treba <tt>#include <cassert></tt>). Táto funkcia umožňuje predpokladať platnosť nejakej podmienky &ndash; ak je táto podmienka splnená, program normálne pokračuje; v opačnom prípade sa program zastaví s chybovou hláškou. Argumentom funkcie <tt>assert</tt> môže byť ľubovoľná booleovská hodnota.
+
V prípade použitia nekorektného vstupu napríklad môžeme celý program ihneď ukončiť. Pohodlný spôsob, ako to spraviť, je použitie funkcie <tt>assert</tt> (treba <tt>#include <cassert></tt>). Táto funkcia kontroluje platnosť nejakej podmienky. Ak je táto podmienka splnená, program normálne pokračuje; v opačnom prípade sa program zastaví s chybovou hláškou. Argumentom funkcie assert môže byť ľubovoľná booleovská hodnota.  
  
 
<syntaxhighlight lang="C++">
 
<syntaxhighlight lang="C++">
Riadok 344: Riadok 211:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
Príklady dvoch behov programu:
 +
<pre>
 +
Zadaj kladne cele cislo: 10
 +
Sucet delitelov 10: 18.
 +
</pre>
 +
 +
<pre>
 +
Zadaj kladne cele cislo: -2
 +
a.out: prog.cpp:6: int sumOfDivisors(int): Assertion `n > 0' failed.
 +
Aborted (core dumped)
 +
</pre>
  
 
=== Úspech výpočtu ako výstupná hodnota ===
 
=== Úspech výpočtu ako výstupná hodnota ===
Riadok 385: Riadok 264:
 
== Programy s viacerými funkciami ==
 
== Programy s viacerými funkciami ==
  
V programe možno volať iba funkcie, ktoré už predtým boli niekde definované alebo aspoň deklarované (tento pojem si ozrejmíme o chvíľu).  
+
V programe možno volať iba funkcie, ktoré už predtým boli niekde definované.  
  
 
Tento program typicky neskompiluje (vo vnútri <tt>f1</tt> ešte nepozná <tt>f2</tt>)
 
Tento program typicky neskompiluje (vo vnútri <tt>f1</tt> ešte nepozná <tt>f2</tt>)
 
<syntaxhighlight lang="C++">
 
<syntaxhighlight lang="C++">
void f1(void) {
+
void f1() {
 
     f2();
 
     f2();
 
}
 
}
  
void f2(void) {
+
void f2() {
     cout << "Hello, World!" << endl;
+
     cout << "Hello, world!" << endl;
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Riadok 400: Riadok 279:
 
Tento program je v poriadku:
 
Tento program je v poriadku:
 
<syntaxhighlight lang="C++">
 
<syntaxhighlight lang="C++">
void f2(void) {
+
void f2() {
     cout << "Hello, World!" << endl;
+
     cout << "Hello, world!" << endl;
 
}
 
}
  
void f1(void) {
+
void f1() {
 
     f2();
 
     f2();
}
 
</syntaxhighlight>
 
 
Program tiež skompiluje v prípade, že každú funkciu pred jej volaním aspoň ''zadeklarujeme'' &ndash; t.j. uvedieme jej hlavičku bez definície jej tela &ndash; a samotnú definíciu funkcie uvedieme až neskôr. V poriadku je teda napríklad aj nasledujúci program:
 
<syntaxhighlight lang="C++">
 
void f2(void);
 
 
void f1(void) {
 
    f2();
 
}
 
 
void f2(void) {
 
    cout << "Hello, World!" << endl;
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>

Aktuálna revízia z 15:49, 30. september 2023

Oznamy

Program na dnes:

  • oznamy
  • teoretické cvičenie (krátky test)
  • vzorové riešenia testu
  • dokončenie minulej prednášky

Čo nás čaká v najbližších dňoch

  • zajtra hlavné cvičenia, rozcvička na funkcie (pozrite si pred cvičením)
  • v stredu prednáška o poliach
  • v piatok doplnkové cvičenia: povinné pre tých, čo v utorok na cvičení nezískajú aspoň 5 bodov

Dnešné teoretické cvičenie

  • krátky bodovaný testík, počíta sa do cvičení (spolu 4 body, cca 1% známky)
  • ciele: zopakovať si učivo, rozmýšľať nad hotovými programami bez kompilovania a spúšťania programu, tréning na semestrálny test
  • môžete používať pero a ťahák vo forme jedného obojstranne popísaného listu A4

Opakovanie

Funkcia je samostatný kus kódu (postupnosť príkazov) s určitým menom. Po zavolaní funkcie jej menom sa daná postupnosť príkazov vykoná.

  • Umožňujú vytvoriť „skratku” pre často používané časti kódu, ktoré tak nie je nutné zakaždým písať nanovo.

Definícia funkcie pozostáva z nasledujúcich častí:

  • Typ návratovej hodnoty funkcie (napríklad double, int, void)
  • Identifikátor funkcie (použite výstižný názov)
  • Zoznam vstupných parametrov funkcie a ich typov
  • Telo funkcie (príkazy v { })
  • Príkaz return vracia návratovú hodnotu funkcie a ukončí jej beh

Platnosť lokálnych premenných je obmedzená na funkciu (alebo blok) v ktorej boli zadefinované. Globálne premenné je možné používať vo všetkých funkciách, zvyčajne sa chceme ich použitiu vyhnúť.

Odovzdávanie parametrov

  • Hodnotou: parametre sa nakopírujú, ďalej fungujú ako lokálne premenná funkcie (napr. double x)
  • Referenciou: parameter je nové meno pre premennú z volajúcej funkcie (napr. double &x)

Odovzdávanie parametrov hodnotou

Vstupné parametre funkcií sa správajú ako lokálne premenné danej funkcie. Pri volaní funkcie sa každému parametru priradí určitá hodnota. Uvažujme napríklad funkciu

void f(int a, int b) {
    // ...
}

Pri volaní

f(1, 2);

sa parametru a priradí hodnota 1 a parametru b sa priradí hodnota 2. Tieto sa ďalej správajú ako lokálne premenné funkcie f. Možno ich teda meniť, ale táto zmena sa neprejaví na mieste, odkiaľ funkciu voláme. Tento mechanizmus nazývame odovzdávaním parametrov hodnotou.

Príklad:

#include <iostream>
using namespace std;

void f(int n) {
    n++;
    cout << n << endl;
}

int main() {
    int n = 1;
    f(n);               // Vypise 2
    cout << n << endl;  // Vypise 1
}

Odovzdávanie parametrov referenciou

V prípade, že pred názov niektorého parametra v hlavičke funkcie napíšeme &, parameter sa bude odovzdávať referenciou.

  • Za takýto parameter možno pri volaní funkcie dosadiť iba premennú (kým pri odovzdávaní hodnotou môžeme použiť napríklad aj konštanty alebo iný výraz).
  • Namiesto hodnoty sa funkcii pošle adresa premennej v pamäti (referencia).
  • Funkcia potom bude túto premennú používať pod novým názvom; jej prípadné zmeny sa prejavia aj na mieste, odkiaľ bola funkcia volaná.

Príklad:

#include <iostream>
using namespace std;

void f(int &n) {
    n++;
    cout << n << endl;
}

int main() {
    int n = 1;
    f(n);               // Vypise 2.
    cout << n << endl;  // Vypise 2.
}

Ďalej si ukážeme niekoľko použití odovzdávania parametrov referenciou.

Viac ako jedna návratová hodnota

Odovzdávanie parametra referenciou používame napríklad vtedy, keď potrebujeme vrátiť viac ako jednu výstupnú hodnotu.

Napríklad nasledujúca funkcia mid dostane súradnice dvoch bodov [x1,y1] a [x2,y2] a do parametrov [xm,ym], ktoré sú odovzdané referenciou, uloží súradnice stredu úsečky spájajúcej body [x1,y1] a [x2,y2].

#include <iostream>
using namespace std;

void mid(double x1, double y1, double x2, double y2, 
         double &xm, double &ym) {
    xm = (x1 + x2) / 2;
    ym = (y1 + y2) / 2;
}

int main() {
    double Ax, Ay, Bx, By;
    
    cout << "Zadaj suradnice bodu A: ";
    cin >> Ax >> Ay;
    cout << "Zadaj suradnice bodu B: ";
    cin >> Bx >> By;
    
    double Mx, My;
    mid(Ax, Ay, Bx, By, Mx, My);
    cout << "Stred usecky AB je [" 
         << Mx << ", " << My << "]." << endl; 
}

Funkcia swap

Typickým príkladom použitia odovzdávania parametrov referenciou je funkcia swap, ktorá vymení hodnoty dvoch premenných, ktoré dostane ako parametre.

#include <iostream>
using namespace std;

void swap(int &a, int &b) {
    int tmp = a;
    a = b;
    b = tmp;
}

int main() {
    int x, y;
    cin >> x >> y;
    
    swap(x, y);
    
    cout << "x = " << x << ", y = " << y << endl; 
}

Keby sme funkcii odovzdali parameter hodnotou – čiže by sme funkciu swap definovali s hlavičkou void swap(int a, int b); – vo funkcii main by sa premenné nevymenili.

Ošetrovanie chybných vstupov

Občas môže nastať potreba, aby parametre funkcie spĺňali určité podmienky. V takom prípade môže byť potrebné korektne sa vysporiadať aj so vstupmi, ktoré tieto podmienky nespĺňajú. Ukážeme si teraz zopár možných prístupov k tomuto problému.

Funkcia neošetrujúca chybné vstupy

Uvažujme napríklad nasledujúcu funkciu, ktorá počíta súčet všetkých deliteľov čísla n. Jej základným predpokladom je, že n je kladné celé číslo.

#include <iostream>
using namespace std;

int sumOfDivisors(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        if (n % i == 0) {
            sum += i;    
        }        
    }   
    return sum;  
}

int main() {
    int n;
    cout << "Zadaj kladne cele cislo: ";
    cin >> n;
        
    cout << "Sucet delitelov " << n << ": " 
         << sumOfDivisors(n) << "." << endl;
}

Ak však používateľ zadá na vstupe nejaké záporné číslo, funkcia vždy vráti nulu, čo nie je úplne v súlade s očakávaním. Jednou možnosťou by samozrejme bolo prerobiť funkciu tak, aby pracovala správne aj na záporných vstupoch. Sú však aj situácie, keď podobné riešenie nie je možné. Ukážeme si preto ďalšie spôsoby, ako sa s nekorektným vstupom vysporiadať.

Použitie funkcie assert

V prípade použitia nekorektného vstupu napríklad môžeme celý program ihneď ukončiť. Pohodlný spôsob, ako to spraviť, je použitie funkcie assert (treba #include <cassert>). Táto funkcia kontroluje platnosť nejakej podmienky. Ak je táto podmienka splnená, program normálne pokračuje; v opačnom prípade sa program zastaví s chybovou hláškou. Argumentom funkcie assert môže byť ľubovoľná booleovská hodnota.

#include <iostream>
#include <cassert>
using namespace std;

int sumOfDivisors(int n) {
    assert(n > 0);
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        if (n % i == 0) {
            sum += i;    
        }        
    }   
    return sum;  
}

int main() {
    int n;
    cout << "Zadaj kladne cele cislo: ";
    cin >> n;
        
    cout << "Sucet delitelov " << n << ": " 
         << sumOfDivisors(n) << "." << endl;
}

Príklady dvoch behov programu:

Zadaj kladne cele cislo: 10
Sucet delitelov 10: 18.
Zadaj kladne cele cislo: -2
a.out: prog.cpp:6: int sumOfDivisors(int): Assertion `n > 0' failed.
Aborted (core dumped)

Úspech výpočtu ako výstupná hodnota

Často je ale neprípustné v prípade jediného volania funkcie s nekorektnými vstupmi ukončiť celý program. Chceli by sme teda vrátiť dve hodnoty: samotný súčet deliteľov a indikátor, či boli argumenty zadané správne.

  • Napríklad súčet deliteľov môžeme ukladať do parametra odovzdávaného referenciou.
  • Výstupom funkcie bude booleovská hodnota, ktorá bude true práve vtedy, keď výpočet funkcie prebehol správne (t.j. keď boli zadané správne argumenty). Túto výstupnú hodnotu je potom možné použiť pri volaní funkcie ako známku toho, že hodnota v parametre predanom referenciou je zmysluplná.
#include <iostream>
using namespace std;

bool sumOfDivisors(int n, int &sum) {
    if (n <= 0) {
        return false;
    } else {
        sum = 0;
        for (int i = 1; i <= n; i++) {
            if (n % i == 0) {
                sum += i;    
            }        
        }   
        return true;
    }  
}

int main() {
    int n, sum;
    cout << "Zadaj kladne cele cislo: ";
    cin >> n;
    
    if (sumOfDivisors(n, sum)) { 
        cout << "Sucet delitelov " << n << ": " 
             << sum << "." << endl;
    } else {
        cout << "Zly vstup" << endl;
    }
}

Programy s viacerými funkciami

V programe možno volať iba funkcie, ktoré už predtým boli niekde definované.

Tento program typicky neskompiluje (vo vnútri f1 ešte nepozná f2)

void f1() {
    f2();
}

void f2() {
    cout << "Hello, world!" << endl;
}

Tento program je v poriadku:

void f2() {
    cout << "Hello, world!" << endl;
}

void f1() {
    f2();
}

Funkcia main

Špeciálnou funkciou je v C/C++ funkcia main. Od ostatných funkcií sa odlišuje v nasledujúcom:

  • V programe ju nemožno volať – jediné jej volanie je automatické (začína sa ním beh programu).
  • Výstupná hodnota funkcie main sa interpretuje ako „spôsob ukončenia” programu (napríklad 0 pre korektné ukončenie, iné hodnoty pre chyby).
    • Funkciu main môžeme teda ukončit napríklad príkazom return 0.
  • Funkcia main môže mať aj určité presne špecifikované parametre (viac o tom neskôr).