Vytvoríme niekoľko premenných:
char znak = 'a';
char pole[5] = "ahoj";
Operačný systém určí, na ktorom mieste RAM sa budú nachádzať.
adresa: \#10 \#15 \#19
+----------------------------------------------+
obsah: | 'a' | 4 | 5 | 'a' | 'h' | 'o' | 'j' | 0 | 5 |
+----------------------------------------------+
rozsah: |<--->| |<-------------------------->|
typ: char char[5]
názov: znak pole
Adresu premennej nazývame aj smerník.
Tajomstvo smerníkov je tajomstvo programovania
Premenná, do ktorej si uložíme smerník.
int premenna_typu_int = 2;
int* adresa_premennej_typu_int = &premenna_typu_int;
adresu si môžme poznačiť do smerníkovej premennej
adresa: \#10 \#15 \#19
+--------------------------------------------+
obsah: | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 10 | 0 | 0 |
+--------------------------------------------+
rozsah: |<------------->| |<-------------->|
typ: int int*
názov: premenna_typu_int adresa_premennej_typu_int
int.char.int a = 2;
void* pa = &a;
int* ppa = (int*)pa;
Za behu je možné meniť dátové typy.
*Vráti hodnotu ktorá je na adrese.
Ale musíme použiť operátor dereferencie
int premenna_typu_int = 2;
// Smerníkový typ
int* adresa_premennej_typu_int = &premenna_typu_int;
// Operátor dereferencie
printf("Tam kde ukazuje smernik je hodnota %d\n",*adresa_premennej_typu_int);
int premenna_typu_int = 2;
// Smerníkový typ
int* adresa_premennej_typu_int = &premenna_typu_int;
// Operátor dereferencie na lavej stane
*adresa_premennej_typu_int = 3;
Názov poľa je adresou jeho prvého prvku.
Ľubovoľná adresa môže byť začiatkom poľa.
Názov poľa je adresou jeho prvého prvku.
Ľubovoľná adresa môže byť začiatkom poľa.
int pole[5] = {1,2,3,4,5};
int* zaciatok_pola = pole;
for(int i = 0; i < 5; i++){
if (pole[i] == zaciatok_pola[i]){
printf("Sicko v poriadku\n");
}
else {
printf("Ta...\n");
}
}
int pole[5] = {1,2,3,4,5};
int* zaciatok_pola = pole;
int* druhe_miesto = pole + 1;
int* tretie_miesto = pole + 2;
int* piate_miesto = tretie_miesto + 2;
int pole[5] = {1,2,3,4,5};
int* zaciatok_pola = &pole[0];
int* druhe_miesto = &pole[1];
int* tretie_miesto = &pole[2];
int* piate_miesto = tretie_miesto[2];
Potrebujeme ľubovoľné množstvo pamäte.
+---------+
| main() |
| int pr1 |
| +------------+
| | funkcia1() |
| | int pr2 |
| | +---------------------+
| | | funkcia2(int arg1) |
| | | float pr3 |
| | +---------------------+
| | |
| | +---------------------+
| | | funkcia3(int arg1) |
| | | float pr3 |
| | +---------------------+
| | |
| +------------+
| |
+--------+
void funkcia(int a) {
a = 2;
}
int main(){
int a = 1;
funkcia(a);
}
Keď dopredu nevieme koľko pamäte budeme potrebovať.
Napr. potrebujeme prečítať súbor po riadkoch.
Pri statickej alokácii budeme vždy obmedzení max. veľkosťou riadku, alebo budeme veľmi plytvať.
Existuje jedna "kopa" počas celého behu programu.
Na konci ju (možno) zruší operačný systém.
malloc() alebo calloc().free().Vyhradili sme si 100 bajtov pamäte a ich adresu sme uložili do premennej
mojapamat.
void* mojapamat = malloc(100);
Smerník typu void* je všeobecný smerník, ktorý nehovorí na aký typ
pamäte ukazuje.
free(mojapamat);
Každú vyhradenú pamäť musíme explicitne uvoľniť pomocou free.
int* intpamat = (int*)mojapamat;
intpamat[10] = 1;
// Mam k dispozicii 20 miest typu int
int* intpamat = malloc(sizeof(int) * 20);
intpamat[10] = 1;
free(intpamat);
Prvé miesto:
int prvahodnota = *intpamat;
Tretie miesto:
int tretiahodnota = intpamat[2];
+-------------------+
Pamäť na kope | | | | | | | | | | |
+-------------------+
adresa: \#10 1 \#20
^
|
+---------------------------+
|
Pamäť na stacku |
|
názov premennej: poleznakov |
typ premennej: char* |
+--------------+ |
hodnota: | 10 | -----------+
+--------------+
adresa: \#100 \#108
char* poleznakov = (char*)calloc(1,100);
poleznakov[0] = 'a';
free(poleznakov);
reallocchar* poleznakov = (char*)calloc(1,100);
poleznakov[0] = 'a';
poleznakov = realloc(poleznakov,200);
poleznakov[150] = 'b';
free(poleznakov);
Môže spracovať aj reťazec:
int strlen(char* str){
int l = 0;
while(*str != 0){
l++;
}
return l;
}
Reťazec je pole znakov zakončené nulou.
int maximum(int* pole, int sz){
int max = -1000000;
for (int i = 0 ; i < sz; i++){
if (pole[i] > max){
max = pole[i];
}
}
return max;
}
Môže načítať a hlásiť výsledok načítania.
int nacitaj_int(int* vysledok);
// Vrati kladne cislo
// ak sa nacitanie podarilo
// Ak nie vypise spravu a vrati nula
int nacitaj_int(int* vysledok){
int r = scanf("%d",vysledok);
if (r!=1){
printf("Nepodarilo sa.\n");
return 0;
}
return 1;
}
Umožňuje pracovať s ľubovoľnými dátami
int compare(const void* p1,const void* p2){
// Zmením typ smerníka
int* pa = (int*)p1;
int* pb = (int*)p2;
// Skopírujem hodnoty
int a = *pa;
int b = *pb;
return b - a;
}
// Toto nefunguje
int nacitaj_int(int vysledok){
// Vysledok je lokalna premenna
int r = scanf("%d",&vysledok);
if (r!=1){
printf("Nepodarilo sa.\n");
return 0;
}
// Ked skoncim, vysledok sa zabudne
return 1;
}
int pole[5] = {1,2,3,4,5};
int* neplatne_miesto = pole + 10;
printf("Hodnota %d\ je nedefiovana, lebo adresa %p mi nepatri\n",*neplatne_miesto,neplatne_miesto);
(Skoro) nikto Vás neupozorní, že pracujete s nedefinovanou hodnotou.
Len program sa správa nepredvídateľne.
Používame Valgrind, upozorní nás na problémy s pamäťou.
Aj keď sa veľa sťažuje....
realloc.free.