Slides
- C nehlídá meze při přístupu: (Ok pro kompilátor, může nastat vyjímka, ale nemusí)
int array[10];
array[100] = 1;
- Dynamická alokace
- proměnná typu ukazatel
int *pArray;
- místo na pole alokujeme (a odebíráme) pomocí speciálních funkcí na haldě (heap)
- Deklerace pole s variabilní délkou
- variable length array (VLA)
- až od C99
- alokuje se na zásobníku
- není nutné starat se o uvolnění (lokální proměnná)
- nedoporučuje se pro přiliš velká pole (použít haldu)
- nedoporučuje se používat pro hodnotu zadanou uživatelem bez důkladné kontroly (příliš velké)
int arraySize = 20;
scanf("%d", &arraySize);
int arrayLocal[arraySize];
arrayLocal[10] = 9;
- Aritmetické operátory prováděné nad ukazateli
- využívá se faktu, že
array[X] je definován jako *(array + X)
- Operátor
+ přičítá k adrese na úrovni prvků pole
- Nikoli na úrovni bajtů!
- Nař. pokud je
array je typ int *, tak se přičte X * sizeof(int)
- Zápis do pole bez specifikace místa
int array[10]; array = 1;
- proměnnou typu pole nelze naplnit
- Zápis těsně za konec pole, častý “N+1” problém
int array[N]; array[N] = 1;
- v C pole se indexuje od 0
- Zápis za konec pole
- např. důsledek ukazatelové aritmetiky nebo chybného cyklu
int array[10]; array[someVariable + 5] = 1;
- Zápis před začátek pole
- méně časté, ukazatelová aritmetika
- Pravoúhlé pole NxM
- stejný počet prvků v každém řádku
int array[N][M];
array2D[row][col] → array1D[row * NUM_COLS + col];
array3D[x][y][z] → array1D[x*(NUM_Y*NUM_Z) + y*NUM_Z + z];
- Pole, které nemá pro všechny “řádky” stejný počet prvků
- dosahováno typicky pomocí dynamické alokace
- lze ale i pomocí statické alokace (řádek nebude delší než
x)
- Ukazatel na pole
- Pole ukazatelů
- pole položek typu ukazatel
int *pArray1D[4];
- jak reprezentovat sekvenci bitů
- dán během výpočtu
- jak měnit typy
- které typy mohou být použité danou operací
- abstrakci - nemusímě přemýšlet na úrovni bitů
- operace nad nečekanými typy - string vs int
- možnost optimalizace
- Implictiní konverze proběhne bez dodatečného příkazu programátora - type corcion
- Explicitní konverzi vynucuje programáor
float value = (float) 5 / 9;
- Vyhodnocování výrazu
int value = 9.5;
- Předání argumentů funkci
void foo(cloat param);
foo(5);
- Návratové hodnotě funkce
double foo() { return 5; }
- Proměnné daného typu můžou vyžadovat zarovnání v paměti (závislé na architektuře)
char na každé adrese
int např. na násobcích 4
float např. na násobních 8
- Pokus o přístup na nezarovnanou paměť dříve způsoboval pád programu
- nyní jádro OS obslouží za cenu výrazného zpomalení
- Paměťový aliasing
- na stejné místo v paměti více ukazatelů s různým typem
- Striktnější varianta: Strict aliasing
- žádné dvě proměnné různého typu neukazují na stejné místo
- zavedeno z důvodu možnosti optimalizace
- standard vyžaduje, ale lze vypnout
- https://en.wikipedia.org/wiki/Aliasing_(computing)
- Buď na bitové nebo sémantické úrovni
- Bitová úroveň vezme bitovou reprezentaci původní hodnoty a interpretuje ji jako hodnotu nového typu
- není ztrátová (pokud do paměti nepíšeme)
- pole
flaot jako pole char
flaot jako int
float fArray[10];
char *cArray = (char *)fArray;
- Sémantická úroveň “vyčte” hodnotu původního typu a “uloží” jo do nového typu
- např.
int a float jsou v paměti realizovány výrazně odlišně (dvojkový doplň. kód vs IEEE 754)
5.4 typu double → float je bezztráty vs 5.4 float na int je ztrátová
- může být ztrátová (ale nusí vždy být)
- výrazný rozdíl oproti bitové konverzi
- Ukazatele lze přetypovat - bitové přetypování, mění se interpretace, nikoli hodnota
- Některé funkce mohou pracovat i bez znalosti datového typu
- např. nastavení všech bitů na konkrátní hodnotu
- např. bitové operace (
^, &, …)
- Je zbytečné definovat separátní funkci pro každý datový typ
- namísto specifickéh typu ukazatele se použije
void *
void *memset( void *ptr, int value, size_t num );
int array[100];
memset( arary, 0, sizeof(array) );
- Typová kontrola výrazně snižuje riziko chyby
- nedovolí nám dělat nekorektní operace
- klíčová vlastnost moderních jazyků
- Explicitní přetypování obchází typový systém
- programátor musí vuyžít korektně, jinak problém
- Snažet se obejít bez typové konverze (automatické i explicitní)
- Napsát kód zavisející na automatické konverzi
- Preferujeme explicitní konverzi před implicitní (čitelnější a jednoznačnější)