Práce s pamětí a předávání parametrů Úvod do programování 1
Motivace Zatím jsme se setkali s následjícími problémy : Proměnná existje / je dostpná jen v blok, kde vznikla Pole existje v blok, kde bylo vytvořeno int *fnkce(int a, int b) { int c = a + b; int pole[] = { a, b ; retrn &c; // NEJDE!!! retrn &a; // NEJDE!!! retrn pole; // NEJDE!!! Pole msí být vytvořeno o velikosti zadané v době kompilace int *vytvor_pole(int velikost){ int pole[velikost]; // NEJDE!!! retrn pole; // NEJDE!!! 2
Obecný kazatel Ukazatel bez vedení typ, se kterým bde moci pracovat void *pamet; Nelze s ním provádět aritmetické operace ani dereferenci int pole[3]; pamet = pole; pamet++; // NEJDE!!! int cislo = 5; void *kazatel = &cislo; *kazatel = 7; // NEJDE!!! Po přetypování je již možné provádět vše ((int *)pamet)++; *((int*)kazatel) = 7; 3
Dynamické alokování paměti Provádíme například pomocí fnkce malloc Jediný parametr dává velikost paměti, ktero chceme alokovat (v bytech) Výsledek volání fnkce je kazatel na začátek přidělené paměti (void *) Nebo NULL v případě neúspěch alokace int *pole; pole = malloc(40); // alokace 40 byt pole = malloc(10 * sizeof(int)); // spravne pole = (int *)malloc(10 * sizeof(int)); // jeste lepsi pole[0] = 10; pole[9] = 42; 4
Příklad požití Fnkce vracející pole drhých mocnin čísel ze vstpního pole: int *powers(int *inpt, int cont) { int i; int *otpt = (int *)malloc(sizeof(int) * cont); // int otpt[cont]; -> toto nefngje for (i = 0; i < cont; i++) { otpt[i] = inpt[i] * inpt[i]; retrn otpt; 5
Další možnosti alokace Fnkce void *calloc(size_t items, size_t size) alokje paměť pro items prvků o velikosti size tedy items*size bytů navíc tto paměť vyplní nlami Fnkce void *realloc(void *old, size_t size) zajišťje změn velikosti dříve alokovaného blok paměti old na velikost size data původního blok paměti bdo zkopírována Všechny zmíněné fnkce najdete v knihovně stdlib.h 6
Uvolnění paměti Pokd alokovano paměť (pomocí malloc, calloc, realloc) nepotřebjeme, měli bychom ji volnit Jinak bde nedostpná až do konce program Toto může způsobit reálného softwar značné problémy K volnění paměti se požívá fnkce void free(void *block) Příklad: int *cisla = (int *)calloc(velikost, sizeof(int)); // tady pole cisla k necem požijeme // a kdyz z neni potreba free(cisla); 7
Příklad práce s pamětí const int b_length = 100; /* block length */ int *data, *h; int b_cont = 1; /* block cont */ data = (int *)malloc(b_length * sizeof(int)); if (data == NULL) retrn 1; /* chyba */ b_cont++; h = (int *) realloc(data, b_cont * b_length * sizeof(int)); if (h == NULL) retrn 1; /* chyba */ else data = h; free(data); 8
Parametry a návratová hodnota Běžně fnkce vrací jeden výsledek pomocí své návratové hodnoty int socet(int a, int b) { retrn a + b; Změny parametrů v těle fnkce se neprojeví v místě volání fnkce int nsd(int a, int b){ while (b){ int r = a % b; a = b; b = r; retrn a; int prvni = 84, drhe = 120; printf("%i", nsd(prvni, drhe)); 9
Pole jako parametr fnkce Troch jinak se chová jako parametr fnkce pole void na2(int cisla[], int pocet){ for (int i = 0; i < pocet; i++) cisla[i] *= cisla[i]; int data[] = { 1, 2, 3, 4, 5 ; na2(data, 5); for (int i = 0; i < 5; i++) printf("%i, ", data[i]); Proč? 10
Parametr předávaný odkazem Stejného princip můžeme požít i jiných typů parametrů void swap(int *a, int *b){ int temp = *a; *a = *b; *b = temp; int prvni = 84, drhe = 120; swap(&prvni, &drhe); Lze vyžít pro fnkce, které mění parametry Nebo mají více návratových hodnot Další výhodo může být nevytváření kopie dat (tj. šetření paměti; především velkých strktr) 11
Předání pole odkazem Pokd bychom chtěli změnit vnitř fnkce samotný kazatel: int vytvor_pole(int pocet, int hodnota, int **vysledek){ *vysledek = (int *)malloc(počet * sizeof(int)); if (*vysledek) for (int i = 0; i < pocet; i++) (*vysledek)[i] = hodnota; else { printf("chyba!"); retrn 1; retrn 0; int *jednicky; vytvor_pole(10, 1, &jednicky); for (int i = 0; i < 10; i++) printf("%i, ", jednicky[i]); 12
Předávání hodnoto vs. odkazem Při předávání hodnoto: Parametr je jen vstpní Typ parametr odpovídá datům Při volání předáváme jakokoli hodnot daného typ Běžný způsob předání parametr void moje_fce(int data){ int cislo; moje_fce(cislo); moje_fce(3 * cislo); Při předávání odkazem: Parametr může být i výstpem Typ parametr je kazatel na typ dat Při volání předáváme adres dat Požíváme pro předávání výstpních parametrů a dále polí (nejde jinak) a velkých strktr void moje_fce(int *data){ int cislo; moje_fce(&cislo); 13