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í.

13 Kapitol
65+ Príkladov
Vedomostí

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 main si vypýtaj počet prvkov poľa N.
  • Dynamicky alokuj pamäť (malloc) pre toto pole a over či pointer nie je NULL.
  • 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.

hello.cC Language
#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

TypFormátPoužitie
int%dCelé čísla (4B)
float%fDesatinné (4B)
double%lfPresné desatinné (8B)
char%cZnak (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.

ALPR Special: Súčet párnych s chytákom
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íš free predtý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 znovu free(p). Okamžitý crash! Fix: po free daj vždy p = 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