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:
booleanv C nie je. Namiesto toho0znamenáfalsea 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 interfaceov 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,csa 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 inty: 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!