Kompletný Sprievodca
Jazykom C
Od prvého riadku až po komplexnú správu pamäte. Tento guide pokrýva nie len to, čo bolo v prednáškach, ale aj reálne best-practices a riešenia z cvičení.
Nové Exam-Štýl Úlohy
Úloha 1: "Konzolový manažér"
Menu pomocou do-while, switch a if.
- Zobraz menu s možnosťami:
1 - Zadaj vek,2 - Vypíš status,0 - Koniec. - Ak používateľ zadá
1, program si vypýta zadať vek. - Ak zadá
2, vypíše či je plnoletý (vek >= 18). Ak nezadal, upozorni ho! - Ak zadá
0, program skončí. Nulou končí aj slučka.
💡 Tip na šablónu
Použi do { ... } while (volba != 0); a vnútri switch (volba) {...}.
Úloha 2: "Dynamický spracovateľ poľa"
Práca s dinamickou pamäťou: malloc, pointre, funkcie a for cyklus.
- V
mainsi vypýtaj počet prvkov poľaN. - Dynamicky alokuj pamäť (
malloc) pre toto pole a over či pointer nie jeNULL. - Cyklom načítaj
Nčísel do poľa. - Funkciou
int spocitaj_kladne(int *pole, int n)vráť počet čísel väčších ako 0. - Na konci bezpodmienečne uvoľni pamäť
free(pole);.
Základy & Štruktúra
C je kompilovaný jazyk. To znamená, že tvoj textový kód musí prejsť cez Compiler (napr. gcc), aby sa stal spustiteľným programom.
#include <stdio.h> // Inklúzia knižnice pre vstup/výstup
int main() { // Hlavná funkcia - tu program začína
printf("Ahoj FEI!\n");
return 0; // Signál úspešného ukončenia
}
Prečo return 0?
V operačných systémoch (Unix/Windows) nula znamená "všetko prebehlo v poriadku". Akékoľvek iné číslo značí chybu.
Typy & Formátovanie
Základné Typy
| Typ | Formát | Použitie |
|---|---|---|
int | %d | Celé čísla (4B) |
float | %f | Desatinné (4B) |
double | %lf | Presné desatinné (8B) |
char | %c | Znak (1B) |
Špeciálne Formáty
%.2f- Zaokrúhli float na 2 des. miesta.%03d- Doplní nuly zľava na 3 miesta (napr. 007).\t- Tabulátor (odsadenie).\n- Nový riadok.
Operátory & Matematika
Logické Operátory
Základ pre každé zložitejšie rozhodovanie (if podmienky).
&&(AND) - Pravda len ak obe strany platia.||(OR) - Pravda ak aspoň jedna strana platí.!(NOT) - Negácia (obráti pravdu na nepravdu).
int vek = 20;
int kredit = 50;
if (vek >= 18 && kredit >= 10) {
printf("Moze nakupovat.\n");
}
Priorita Operátorov
Zátvorky () majú najvyššiu prioritu. Násobenie/delenie má prednosť pred sčítaním.
// 1. Násobenie má prednosť
int a = 5 + 3 * 2; // a bude 11
// 2. Zátvorky menia prioritu
int b = (5 + 3) * 2; // b bude 16
// 3. Priorita v logike (&& vyhodnocuje skor ako ||)
if (x > 5 || y < 10 && z == 0)
// Rovná sa: if (x > 5 || (y < 10 && z == 0))
Podmienky & Rozhodovanie
Rozhodovacie štruktúry umožňujú programu reagovať podľa rôznych stavov.
int body = 85;
if (body >= 90) {
printf("Znamka A\n");
} else if (body >= 80) {
printf("Znamka B\n");
} else {
printf("Opakujes!\n");
}
Cykly & Iterácie
Používajú sa na opakovanie rovnakého kódu viackrát. Na skúškach (ALPR) často vidíme použitie break a continue.
int cislo, sucet = 0;
// Nekonečný cyklus, program vyskočí len pri splnení podmienky (break)
while (1) {
printf("Zadaj cislo (zaporne pre koniec): ");
scanf("%d", &cislo);
if (cislo < 0) {
break; // Okamžite ukončí celý while cyklus
}
if (cislo % 2 != 0) {
continue; // Preskočí tento krok a pokračuje ďalším načítaním
}
// Ak sem kód dobehol, číslo je kladné a párne
sucet += cislo;
}
printf("Sucet parnych: %d\n", sucet);
Polia & Reťazce
Klasické polia
Skupina premenných rovnakého typu uložená súvisle v pamäti.
int cisla[5] = {10, 20, 30, 40, 50};
printf("%d", cisla[0]); // 10 (Indexujeme od nuly!)
Reťazce (Strings) v C
V C neexistuje "string", je to len pole char, ktoré končí špeciálnym nulovým znakom '\0' (null-terminator).
char meno[25] = "Adam";
// Pamäť: ['A']['d']['a']['m']['\0'][?][?]...
Práca so String.h
Knižnica <string.h> obsahuje kľúčové funkcie. Pamätaj: chránený reťazec končí '\0'! Ak tvoje pole nemá nulový znak, funkcie sa "zdivočejú" a program spadne.
#include <string.h>
char buffer[50];
char heslo[] = "admin123";
// 1. Kopírovanie zleva do prava (skopíruje aj \0!)
strcpy(buffer, heslo);
// 2. Dĺžka reťazca (NEPOČÍTA koncový znak \0)
int dlzka = strlen(buffer); // vráti 8
// 3. Porovnanie reťazcov (vráti 0, ak sú prekvapivo ROVNAKÉ)
if (strcmp(buffer, "admin123") == 0) {
printf("Heslo je spravne!\n");
}
Funkcie & Parametre
Funkcie slúžia na to, aby sme neopakovali ten istý kód viackrát. Môžu vracať hodnotu (int, float) alebo aj nevykonať žiadny návrat (void).
float vypocitajZlavu(float povodnaCena) {
float zlava = povodnaCena * 0.20;
return povodnaCena - zlava;
}
int main() {
float konecnaCena = vypocitajZlavu(100.0);
}
Pointery, Adresy & Aritmetika
Pointer je premenná, ktorá uchováva adresu inej premennej. Je to ako mať lístok s číslom skrinky v šatni namiesto toho, aby si nosil celú skrinku so sebou.
int x; | Normálna premenná (vyhradí sa miesto pre int). |
int *p; | Pointer, zatiaľ neukazuje nikam (ideálne = NULL;). |
p = &x; | "p je adresa x" (uloženie adresy premennej x do pointera p). |
*p = 5; | "Na adrese v p zapíš 5" (x sa zmení na 5, lebo p ukazuje na x). |
int x = 42;
int *p = &x; // & = Operátor adresy (KDE to je?)
printf("Cez pointer: %d\n", *p); // * = Dereferencia (ČO je tam?)
Pointerová aritmetika a Polia
Pripočítaním +1 k pointeru sa neposúvame o 1 bajt, ale o 1 prvok daného typu (napr. pri int o 4 bajty).
int A[5] = {10, 20, 30, 40, 50};
int *p = A; // Pole A sa správa ako pointer na prvý prvok
printf("%d\n", *p); // Vypíše 10
printf("%d\n", *(p + 1)); // Vypíše 20 (to isté ako A[1])
p++; // Posunie pointer na ďalší prvok
printf("%d\n", *p); // Vypíše 20
Pointery a Polia vo funkciách
Keď pošleš do funkcie premennú, funkcia si vytvorí kópiu (Pass by Value). Ak chceš zmeniť pôvodný údaj, musíš poslať pointer (Pass by Reference).
// TOTO NEFUNGUJE (a aj b ostanú rovnaké)
void vymenZle(int a, int b) { int tmp = a; a = b; b = tmp; }
// TOTO FUNGUJE (meníme hodnoty priamo na adresách)
void vymenDobre(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
// Volanie: vymenDobre(&x, &y);
Ako funguje posielanie poľa do funkcie?
Polia sa NEnakopírujú celé! Do funkcie sa pošle iba pointer na prvý prvok. Preto vo vnútri funkcie nefunguje sizeof na zistenie veľkosti poľa.
void vypisPole(int pole[], int n) {
// Tu je sizeof(pole) iba veľkosť pointera (napr. 8 bajtov), nie celého poľa!
// Preto vždy musíme posielať aj dĺžku poľa (n).
for(int i = 0; i < n; i++) {
printf("%d ", pole[i]);
}
}
Dynamická alokácia (Heap vs Stack)
Bežné lokálne premenné (int x;, poli int A[100];) vznikajú na Stacku (zásobníku). Majú obmedzenú veľkosť pamäte a zmiznú po skončení funkcie.
Dáta z malloc vznikajú na Heape (halde). Existujú, kým ich vyslovene nezmažeš pomocou free.
int n;
scanf("%d", &n);
// Alokácia poľa n-celých čísel na Heape
int *pole = (int*)malloc(n * sizeof(int));
if (pole == NULL) {
printf("Pamäť nie je k dispozícii! (Heap je plný)\n");
return 1;
}
// TU PRACUJEME S POĽOM (pole[0] = 5...)
free(pole); // VŽDY uvoľni pamäť po skončení!
pole = NULL; // Prevencia proti použitiu už uvoľneného pointera
Štruktúry (struct)
Umožňujú zoskupiť rôzne typy dát pod jeden názov. Napríklad hrdina v RPG hre má meno (string), HP (int) a silu (float).
struct Hrac {
char meno[50];
int hp;
float level;
};
struct Hrac h1 = {"Borec", 100, 1.5};
printf("%s má %d HP.\n", h1.meno, h1.hp);
Súbory (File I/O)
Práca s textovými (.txt) a binárnymi súbormi pomocou pointera typu FILE.
FILE *f = fopen("data.txt", "w"); // w = write (prepísať)
if (f != NULL) {
fprintf(f, "FEI STU MA UČÍ PROGRAMOVAŤ!\n");
fclose(f); // Vždy súbor zatvor!
}
Makrá (#define)
Preprocesor nahrádza text ešte pred kompiláciou. Skvelé pre konštanty a rýchle funkcie.
#define PI 3.14159
#define MSG "Vitaj v C!"
#define STVOREC(x) ((x) * (x))
printf("PI: %f", PI);
printf("Plocha: %d", STVOREC(5));
Typické Chyby (Čo ťa na písomke zabije)
1. %f vs %lf (printf / scanf)
V printf funguje na double aj %f aj %lf. ALE v scanf je to brutálne dôležité!
float f; scanf("%f", &f); // SPRÁVNE
double d; scanf("%lf", &d); // SPRÁVNE
double d; scanf("%f", &d); // CHYBA! Načíta blbosť (smieši sa veľkosť pamäte)
2. = vs == (Priradenie vs Porovnanie)
Typická logická chyba (kompilátor ťa často ani neupozorní).
if (x = 5) { ... } // CHYBA! Vždy true, x sa zmení na 5
if (x == 5) { ... } // SPRÁVNE porovnanie
3. Off-By-One a Buffer Overflow v poliach
Indexovanie od 0!! Ak má pole 5 prvkov, maximálny index je 4.
int pole[5];
for(int i = 0; i <= 5; i++) { // CHYBA! i <= 5 pôjde až po index 5
pole[i] = 0; // Prepisuješ cudzí memory blok (Crash!)
}
4. Zabudnutý Ampersand v scanf
scanf potrebuje *adresu*, kam má dáta zapísať.
int vek;
scanf("%d", vek); // CHYBA! Crash (Segmentation fault)
scanf("%d", &vek); // SPRÁVNE
char meno[20];
scanf("%s", meno); // SPRÁVNE (meno je už pointer/adresa)
5. Memory Leak & Double Free (malloc/free)
- Memory Leak: Zabalil si funkciu, kde spravíš
malloc, ale neurobíšfreepredtým než funkcia skončí a vráti hodnotu. Pamäť je stratená, ale stále zabratá. - Double Free: Ak spravíš
free(p)a neskôr náhodou znovufree(p). Okamžitý crash! Fix: po free daj vždyp = NULL; - Deref po free: Ak robíš
free(p)a neskôr*p = 10;. Opet crash.
Typické Zadania a Šablóny
Šablóna: Nájdenie maxima v dynamicky alokovanom poli
Tento pattern (malloc -> načítanie -> spracovanie -> free) je zlatý štandard pre väčšinu písomiek.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, max;
// 1. Načítanie veľkosti poľa
printf("Zadaj pocet cisel: ");
if(scanf("%d", &n) != 1 || n <= 0) {
printf("Chybny vstup!\n"); return 1;
}
// 2. Dynamická alokácia s prislusnym checkom
int *pole = (int*)malloc(n * sizeof(int));
if(pole == NULL) {
printf("Chyba alokacie!\n"); return 1;
}
// 3. Načítanie hodnôt do poľa
for(int i = 0; i < n; i++) {
scanf("%d", &pole[i]);
}
// 4. Spracovanie (Hľadanie Maxima)
max = pole[0]; // Inicializácia prvým prvkom! (NIE nulu, čo ak su cisla zaporne?)
for(int i = 1; i < n; i++) {
if(pole[i] > max) {
max = pole[i];
}
}
printf("Max je: %d\n", max);
// 5. Uvolnenie pamate
free(pole);
pole = NULL;
return 0;
}
Šablóna: Počítanie znaku v reťazci
Slávny for loop + if pattern na stringy.
char pole[100] = "abrakadabra";
char hladaj = 'a';
int pocet = 0;
// Iterujeme kým nenájdeme koniec reťazca '\0'
for (int i = 0; pole[i] != '\0'; i++) {
if (pole[i] == hladaj) {
pocet++;
}
}
printf("Znak '%c' je tam %d krat.\n", hladaj, pocet);
Šablóna: Filter z poľa do poľa
Vyberáme z jedného poľa do druhého podľa podmienky (napr. len kladné).
int vstup[5] = {-1, 5, -3, 8, 2};
int vystup[5];
int pocetKladnych = 0;
for (int i = 0; i < 5; i++) {
// Vyberieme len ak podmienka platí
if (vstup[i] > 0) {
vystup[pocetKladnych] = vstup[i];
pocetKladnych++; // Index rastie LEN pre výstup!
}
}
// 'pocetKladnych' bude teraz 3. Pole ukrýva 5, 8, 2