Dnes pokračujme radostným seriálom o migrácii z Javy na C. Porozprávajme sa o funkciách a dajme si rovno príklad:
Zistite, či tri úsečky dokážu byť stranami trojuholníka.
Kuk do základoškolského učiva! Má platiť trojuholníková nerovnosť:
a + b > c
b + c > a
c + a > b
Urobme si implementáciu v Jave:
public class Trojuholnik {
public static boolean tvoriaTrojuholnik(double a, double b, double c) {
return (a + b > c) && (b + c > a) && (c + a > b);
}
public static void main(String[] args) {
return Trojuholnik.tvoriaTrojuholnik(3, 4, 5);
}
}
Funkcie v C
Každý program v C má minimálne jednu funkciu: main()
— bezparametrovú a vracajúci int
. (Bokom: main()
môže mať aj viacero parametrov, ale o tom potom).
Pokojne si môžeme dodať aj ďalšie funkcie: stačí sa dohodnúť na dátových typoch a návratových hodnotách.
Java funkcia vracala boolean
. Pamätajme si toto:
boolean
v C nie je. Namiesto toho0
znamenáfalse
a iné číslo znamenátrue
˛.
Funkcia pre strany trojuholníka môže vyzerať takto:
int tvoria_trojuholnik(double a, double b, double c) {
return (a + b > c) && (b + c > a) && (c + a > b);
}
Funkcia je zároveň pekný príklad použitia logických operátorov: napr. výraz a + b > c
sa vyhodnotí buď na nulu (= nepravda) alebo na nejaké kladné či záporné číslo (= pravda). Napr.
printf("%d", 3 < 4);
vráti nejaké nenulové číslo (napr. 1
).
Logické operátory tiež pracujú s číslami v podobnom duchu.
Použitie môže vyzerať takto:
int main(void)
{
if(tvoria_trojuholnik(3, 4, 5)) {
printf("Strany tvoria trojuholnik");
} else {
printf("Strany NETVORIA trojuholnik");
}
return EXIT_SUCCESS;
}
Aha, sám if
, ktorý v Jave berie booleovský výraz, pracuje na číselnej filozofii.
Celý zdroják bude teda takýto:
#include <stdio.h>
#include <stdlib.h>
int tvoria_trojuholnik(double a, double b, double c) {
return (a + b > c) && (b + c > a) && (c + a > b);
}
int main(void)
{
if(tvoria_trojuholnik(3, 4, 5)) {
printf("Strany tvoria trojuholnik");
} else {
printf("Strany NETVORIA trojuholnik");
}
return EXIT_SUCCESS;
}
Poradie funkcií
V Jave platí fintivá vlastnosť, že metódy môžu byť v triede uvádzané v ľubovoľnom poradí. Nie tak v C. Spravme zámenu metód!
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
if(tvoria_trojuholnik(3, 4, 5)) {
printf("Strany tvoria trojuholnik");
} else {
printf("Strany NETVORIA trojuholnik");
}
return EXIT_SUCCESS;
}
int tvoria_trojuholnik(double a, double b, double c) {
return (a + b > c) && (b + c > a) && (c + a > b);
}
Kompilácia zlyhá:
error: implicit declaration of function 'tvoria_trojuholnik'
(Ale ak nemáte nastavené žiadne -Wall
, -Wextra
a podobne, tak dostanete len varovanie a program sa skompiluje a zrejme aj zbehne.)
Funkcia main()
čaká, že v zdrojáku pred ňou sa nájde funkcia tvoria_trojuholnik
, aby mohol overiť počet parametrov, ich typy a návratovú hodnotu. Ak funkciu nenájde, bude predpokladať, že tvoria_trojuholnik
zožerie ľubovoľný počet parametrov a bude vracať int
. To je síce v tomto prípade schváliteľné, ale v prípade zložitejších funkcií to môže viesť ku kadejakým divných chybám.
Platí zásada:
Funkcie, ktoré majú telo za prvým použitím, musia mať pred použitím deklarovanú hlavičku.
Takto:
#include <stdio.h>
#include <stdlib.h>
int tvoria_trojuholnik(double a, double b, double c);
/*´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´*/
int main(void)
{
if(tvoria_trojuholnik(3, 4, 5)) {
printf("Strany tvoria trojuholnik");
} else {
printf("Strany NETVORIA trojuholnik");
}
return EXIT_SUCCESS;
}
int tvoria_trojuholnik(double a, double b, double c) {
return (a + b > c) && (b + c > a) && (c + a > b);
}
Hlavička je teda dvakrát: raz na začiatku a raz na konci. Toto správanie jepredobraz filozofie interface
ov z Javy: najprv uvediete všetky hlavičky funkciá a potom ich implementácie.
Parametre funkcií
Ak funkcia neberie žiadne parametre, nezabudnite uviesť do zátvoriek void
. Ak funkcia nevracia nič, návratová hodnota je void
:
void pozdrav(void) {
printf("Huh?");
}
Parametre, ktoré sa nepoužívajú
Niekedy sa stane, že máte vo funkcii viacero parametrov, ale nie všetky chcete použiť. Ak ste si pozapínali všetky varovania ako chyby, máte problém:
void pozdrav(int pocet_pozdraveni) {
printf("Huh?");
}
To znamená:
main.c:4: error: unused parameter 'pocet_pozdraveni'
Riešenie spočíva v šialenom triku:
void pozdrav(int pocet_pozdraveni) {
(void) pocet_pozdraveni;
printf("Huh?");
}
Nepoužitý parameter pretypujeme na void
, čím zahlásime, že ho budeme ignorovať a kompilátor bude spokojný.
Odovzdávanie parametrov
V C sa všetky parametre odovzdávajú hodnotou. Ak máme našu funkciu:
int tvoria_trojuholnik(double a, double b, double c) {
/*....*/
}
a zavoláme ju s parametrami 3, 4, 5, tak v skutočnosti sa stane toto:
- V programe sa za behu po zavolaní funkcie uchmatne z pamäte (na zásobníku) priestor pre tri premenné typu
double
:a
,b
,c
. - Do nich sa nakopírujú hodnoty
3
,4
,5
. - Prebehne výpočet, funkcia skončí. Pamäť s premennými
a
,b
,c
sa automaticky uvoľní.
Klasický školský príklad hovorí:
#include <stdio.h>
#include <stdlib.h>
void vymen(int a, int b) {
int c = a;
a = b;
b = c;
}
int main(void)
{
int hodnota1 = 1;
int hodnota2 = 42;
vymen(hodnota1, hodnota2);
printf("%d %d", hodnota1, hodnota2);
return EXIT_SUCCESS;
}
Vypíše to…
1 42
Beh je totiž jasný: po zavolaní vymen()
sa vyhradí pamäť pre dva int
y: do prvého sa nakopíruje obsah premennej hodnota1
a do druhého hodnota2
, čiže
a <- 1
b <- 42
Funkcia dobehne a skončí v takomto stave:
a = 42
b = 1
c = 42
V tej chvíli sa pamäť uvoľní, obsahy premenných sa zahodia a obsahy v hodnota1
a hodnota2
ostanú nezmenené.
Toto sa samozrejme dá zmeniť, ale na to potrebujeme smerníky/pointery, o ktorých neskôr.
Návratové hodnoty funkcií
Kúzelné je takéto správanie
int vrat_daco(void) {
/* nerobíme nič */
}
V Jave by už kompilátor frflal, že funkcia vracia int
… ale žiadny nevracia a teda, že musí mať nejaký return
. V C to nie je chyba, akurát funkcia bude mať nedefinovanú návratovú hodnotu. Ak zapnete pri kompilácii štandardné varovanie -Wall
, budete na to upozornení.
Záver
Rozobrali sme si všetko, čo bolo treba, nabudúce polia!