Návratová hodnota funkce main
Již víme, že main je funkce kterou volá operační systém po spuštění programu.
Návratová hodnota typu int
je určena pro operační systém který je touto
hodnotou informován o případné chybě. Pokud funkce main
vrátí 0, tak to
znamená že v programu nenastala žádná chyba. Jíné hodnoty reprezentují kódy
jednotlivých chyb.
Parametry funkce main
Funkce main
může mít žádný, nebo dva formální parametry.
Jmenují se argc
(argument count) a argv
(argument vector)
a definují se následovně:
int main(int argc, char* argv[]);
Tyto argumenty předá operační systém, my je můžeme specifikovat v příkazové řádce:
./program.exe -c 10 "text s mezerou"
Hodnota argc bude rovna 4 – počet předaných argumentů včetně názvu programu.
V argv
bude uloženo:
argv[0] = "./program.exe";
argv[1] = "-c";
argv[2] = "10";
argv[3] = "text s mezerou";
Na prvním místě je uložen název programu. Ostatní argumenty jsou odděleny mezerou. Pokud chceme mezeru jako součást argumentu, přidáme uvozovky.
Čísla jako argumenty
Pozor na to, že i čísla se předávají jako řetězec. Pokud chceme použít
číslo opravdu jako číslo, je nutné ho zkonvertovat pomocí funkcí atoi
("array to integer") a atof
("array to float"). Jsou v knihovně stdlib.h
.
Deklarace funkcí:
double atof (const char* str);
int atoi (const char* str);
// Příklad
int number = atoi("245") + atoi("55"); // 300
double double_number = atof("245.47") - atof("0.47"); // 245
Koncepce programu
Zatím jsem vytvářeli jeden program v jednom souboru, což je nepraktické.
V praxi dělíme různé části programu do samostatných souborů. V podstatě už
to znáte: v knihovně stdio
jsou funkce pro vstup/výstup, v string
jsou funkce pro práci s řetězci atp.
Otázka zní, jakým způsobem můžeme vytvářet podobné knihovny?
Rozdělení do více souborů
Někoho by mohlo napadnout rozdělit funkce do dvou soborů main.c
a functions.c
a pak tento soubor pomocí již známého #include
vložíme do souboru main.c
.
functions.c
int sum(int a, int b) {
return a + b;
}
main.c
#include <stdio.h>
// Obsah souboru functions.c by se vložil na místo řádku s
// #include "functions.c"
#include "functions.c"
int main() {
printf("2 + 3 = %i\n", sum(2, 3));
return 0;
}
Soubor by tedy vypadal následovně:
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
int main() {
printf("2 + 3 = %i\n", sum(2, 3));
return 0;
}
Tohle je ale špatné řešení! Chceme docítil odděleného překladu – abychom byli schopni
upravit soubor functions.c
, aniž bychom museli nutně přeložit soubor main.c
.
Hlavičkový soubor
Místo vkládání souboru se zdrojovým kódem používáme hlavičkové .h soubory. Vytvoříme soubor functions.h, do kterého vložíme deklarace funkcí, které jsou v souboru functions.c, které chceme použít:
functions.h
int sum(int, int);
Pomocí hlavičkového souboru říkáme překladači, jaké funkce mohou být použity ale jejích definice budou dodáný "pozdějí". Naše souboty tedy vypadají následovně:
functions.c
int sum(int a, int b) {
return a + b;
}
functions.h
int sum(int, int);
main.c
#include <stdio.h>
#include "functions.h"
int main() {
printf("2 + 3 = %i\n", sum(2, 3));
return 0;
}
Jak zabránit vícenásobnému vložení
Může se stát, že dva různé soubory vkládají jednu a tutéž knihovnu,
což je obecně nežádoucí. K zabránění druhého vložení můžeme použít trik s #ifndef
v hlavičkovém souboru.
Můžeme modifikovat soubor functions.h:
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
int sum(int, int);
#endif
Oddělený překlad pomocí objektových souborů
Na obrázku níže je znázorněno jak probíhá překlad.
Ze souborů se zdrojovými kódy .c
se vytvoří objektový soubor .obj
A tyto objektové soubory jsou sloučeny do jednoho spustitelného souboru.
Pokud uděláme změnu v souboru functions.c
, tak pak jen stačí
zkompilovat functions.c
a functions.h
do souboru
fucntions.obj
a poté zavolat Linker, aby sloučil nově zkompilovanou
část programu a původní.
Oddělený překlad v příkazovém řádku
Oddělený překlad provádí většina vývojových prostředí automaticky. Podíváme se tedy na oddělený překlad pomocí příkazové řádky a překladače gcc.
gcc -c main.c
gcc -c functions.c
gcc main.o functions.o -o program
./program
2 + 3 = 5
Poznámky na konec
- V hlavičkovém souboru nemusí být pomocné funkce a obecně funkce, které nechceme sdílet.
- V hlavičkovém souboru mohou být i další věci – typy definované přes
typedef
, které chceme veřejně sdílet, konstanty apod. - Pokud např.
fractions.c
pracuje s typemFraction
a my tento typ chceme použít i v souborumain.c
, musí být typFraction
definován už vfractions.h
. - Samotný soubor
fractions.h
může vložit (pomocí#include
) svůj hlavičkový soubor.
Úkoly
Napište v jazyku C program pro výpočet objemu a povrchu válce, pravidelného trojbokého, čtyřbokého a šestibokého hranolu. Parametry výpočtu by mělo být možné předávat programu při spuštění z příkazové řádky. Zdrojový kód programu by měl být rozdělen do 2 modulů. Modul hlavní funkce (soubor main.c) bude zajišťovat zpracování a případně načtení chybějící parametrů výpočtu, budou z něj volány funkce zajišťující vlastní výpočet a vypisovány vypočítané hodnoty na obrazovku. Druhý modul (soubory geom.h a geom.c) pak bude zajišťovat veškeré požadované výpočty.
Příklad použití:
geometry.exe 0 1.2 2.4 (OS Windows)
./geometry 0 1.2 2.4 (OS Linux)
// Výstup
Valec s vyskou 1.2 a polomerem podstavy 2.4 ma povrch 54.2592 a objem 21.7037.
main.c
, kde navíc implementujete funkci
check_brackets
s následující hlavičkou:
int check_brackets(char *math_expression)
Tato funkce zkontroluje, zda v matematickém výrazu jsou správně použity závorky. Pokud ano tak funkce vrací 1 jinak 0.
Příklad
check_brackets("[(1 + 3) * (1 + (2 + 4))]") // -> return 1
check_brackets("[(1 + 3)] * (1 + (2 + 4})]") // -> return 0