240 likes | 432 Views
KAZALCI. Milan Ojsteršek. KAZALCI. Kazalci predstavljajo spremenljivke, katerih zaloga vrednosti so pomnilniški naslovi. To omogoča, da obravnavamo naslov pomnilniške lokacije kot spremenljivko. int y = 5; y 445
E N D
KAZALCI Milan Ojsteršek
KAZALCI Kazalci predstavljajo spremenljivke, katerih zaloga vrednosti so pomnilniški naslovi. To omogoča, da obravnavamo naslov pomnilniške lokacije kot spremenljivko. int y = 5; y 445 int *ykaz; - kazalec na pomnilniške lokacije, kjer so shranjena cela števila 5
KAZALCI – prireditev naslova ykaz = &y; - prireditev naslova, kjer je shranjenavrednost spremenljivke y (to je vrednost 5) 445 5 y 445 ykaz 412
KAZALCI – ozemljitev kazalca int *ykaz=NULL; - inicializacija vrednosti kazalca - kazalec ne kaže nikamor - kazalca int y1 = *ykaz; - dereferenciranje kazalca NULL ykaz 5 445 445 5 y1 ykaz
KAZALCI – generiranje novega objekta ykaz = new int; - generiranje novega kazalca - alocira se prostor za novo pomnilniško lokacijo, na katero kaže kazalec primer: double *ykaz; ykaz = new double(5.16); // dodelitev pomnilnika in inicializacija vrednosti Objekt Kazalec Pred iizvedbo ukaza new 321 NULL Po izvedbi ukaza NEW 415 5.16 415 ykaz 321 ykaz
KAZALCI – brisanje objekta delete ykaz; // sprosti pomnilniško lokacijo, na katero kaže kazalec NULL 321 Po izvedbi ukaza delete ykaz
#include <iostream.h> main() { int a; // a je celo stevilo int *kaz_a; // kaz_a je kazalec na celo stevilo a = 7; kaz_a = &a; // kaz_a nastavljen na naslov od a cout << "Naslov od a je " << &a << endl << "Vrednost od kaz_a je " << kaz_a << endl << endl; cout << "Vrednost od a je " << a << endl << "Vrednost od *kaz_a je " << *kaz_a << endl << endl; cout << "Dokaz, da sta * in & nasprotna drug " << "drugemu." << endl << "&*kaz_a = " << &*kaz_a << endl << "*&kaz_a = " << *&kaz_a << endl; return 0; }
Aritmetika s kazalci Osnovno pravilo aritmetike s kazalci je, da se naslov izračuna odvisno od velikosti objekta, na katerega kaže kazalec: vrednost kazalca + sizeof(tip kazalca) * i
Predpostavimo, da naš prevajalnik shrani realno število v štirih zlogih. // Operator sizeof pri uporabi z imenom // polja vrne stevilo zlogov v polju. #include <iostream.h> main() { float polje[20]; cout << "Stevilo zlogov v polju je " << sizeof(polje) << endl; return 0; }
Operacije s kazalci Možne so naslednje operacije: ++ - inkrementiranje kazalca -- - dekrementiranje kazalca + - prištevanje celega števila - - odštevanje celega števila += - dodajanje celega števila -= - odvzemanje celega števila Pri odštevanju kazalcev dobimo celoštevilčno vrednost, sicer pa novi kazalec.
Polja in kazalci Predpostavimo naslednjodeklaracijo: const int velikost = 100; int b[velikost], *kaz_b; Predpostavimo, da je začetna lokacija polja 3000. Predpostavimo tudi, da naš prevajalnik shrani celo število v štirih zlogih. Ekvivalentni stavki so: kaz_b = b; in kaz_b = &b[0]; Oba stavka priredita spremenljivki kaz_b vrednost 3000. kaz_b = b + 1; in kaz_b = &b[1]; Oba stavka priredita spremenljivki kaz_b vrednost 3004.
// Uporaba indeksiranega in kazalcnega zapisa s polji #include <iostream.h> main() { int b[] = {10, 20, 30, 40}; int *kaz_b = b; // nastavitev kaz_b, da kaze // na polje b cout << "Polje b izpisano s:" << endl << "poljsko-indeksiranim zapisom" << endl; for (int i = 0; i <= 3; i++) cout << "b[" << i << "] = " << b[i] << endl; cout << endl << "kazalcnim zapisom z odmikom, kjer" << endl << "je kazalec ime polja" << endl;
for (int odmik = 0; odmik <= 3; odmik++) cout << "*(b + " << odmik << ") = " << *(b + odmik) << endl; cout << endl << "kazalcno-indeksiranim zapisom" << endl; for (i = 0; i <= 3; i++) cout << "kaz_b[" << i << "] = " << kaz_b[i] << endl; cout << endl << "kazalcnim zapisom z odmikom" << endl; for (odmik = 0; odmik <= 3; odmik++) cout << "*(kaz_b + " << odmik << ") = " << *(kaz_b + odmik) << endl; return 0; }
Nizi znakov s kazalci Podobno lahko pri definiciji namesto polja znakov: char niz[] = "Srečno novo leto"; uporabimo char* niz = "Srečno novo leto"; Obe definiciji rezervirata toliko znakov, kot je število znakov niza in en dodaten ničelni znak. Razlika med definicijama je, da prvi predstavlja identifikator niz naslov prvega elementa polja, v drugi pa je identifikator niz kazalec, ki vsebuje naslov rezerviranega polja znakov.
#include <iostream.h> void izpisi_znake(const char *); main() { char niz[] = "izpis niza znakov"; cout << "Niz je:" << endl; izpisi_znake(niz); cout << endl; return 0; } // V funkciji izpisi_znake je kaz_niz kazalec na //nespremenljiv znak. Znakov se ne da spremeniti preko //kaz_niz (kaz_niz je torej kazalec s pravico le do //branja). void izpisi_znake(const char *kaz_niz) { for ( ; *kaz_niz != '\0'; kaz_niz++) cout << *kaz_niz; }
Dinamične podatkovne strukture class vozlisce { public: int podatek; vozlisce* k_naslednji; };
Dinamične podatkovne strukture Začetek 1 main() { vozlisce* zacetek; vozlisce* vmesni; vozlisce* prvi; // kreiranja prvega vozlisca zacetek = new vozlisce; zacetek->podatek = 1; zacetek->k_naslednji = NULL; prvi = zacetek; // kreiranje drugega vozlisca vmesni = new vozlisce; vmesni->podatek = 2; vmesni->k_naslednji = zacetek; zacetek = vmesni; Null Prvi
Dinamične podatkovne strukture VMESNI 2 main() { vozlisce* zacetek; vozlisce* vmesni; vozlisce* prvi; // kreiranja prvega vozlisca zacetek = new vozlisce; zacetek->podatek = 1; zacetek->k_naslednji = NULL; prvi = zacetek; // kreiranje drugega vozlisca vmesni = new vozlisce; vmesni->podatek = 2; vmesni->k_naslednji = zacetek; zacetek = vmesni; Začetek 1 Prvi Null
// izpis podatkov prvih dveh vozlisc cout << "Prvi vneseni podatek: " << zacetek->k_naslednji->podatek << endl << "Drugi vneseni podatek: " << zacetek->podatek << endl; //kreiranje tretjega vozlisca vmesni = new vozlisce; vmesni->podatek = 3; vmesni->k_naslednji = zacetek; zacetek = vmesni;
// izpis podatkov prvih treh vozlisc cout << "Prvi vneseni podatek: " << prvi->podatek << endl << "Drugi vneseni podatek: " << zacetek->k_naslednji->podatek << endl << "Tretji vneseni podatek: " << zacetek->podatek << endl; // brisanje zadnjega vnesenega vozlisca zacetek = zacetek->k_naslednji; delete vmesni; vmesni =zacetek; // izpis podatkov prvih dveh vozlisc cout << "Prvi vneseni podatek: " << zacetek->k_naslednji->podatek << endl << "Drugi vneseni podatek: " << zacetek->podatek << endl;
// brisanje predzadnjega vnesenega vozlisca zacetek = zacetek->k_naslednji; delete vmesni; vmesni =zacetek; // brisanje predpredzadnjega vnesenega vozlisca zacetek = zacetek->k_naslednji; delete vmesni; return 0; }
Podobno lahko naredimo kreiranje, izpis in brisanje 10 elementov seznama. { vozlisce* zacetek; vozlisce* vmesni; // kreiranja prvega vozlisca zacetek = new vozlisce; zacetek->podatek = 1; zacetek->k_naslednji = NULL; // kreiranje preostalih devtih elementov seznama for (int i=2; i<=10; i++) { vmesni = new vozlisce; vmesni->podatek = i; vmesni->k_naslednji = zacetek; zacetek = vmesni; };
// izpis seznama desetih elementov vmesni = zacetek; for ( i=1; i<=10; i++) { cout << vmesni->podatek << endl; vmesni = vmesni->k_naslednji; }; // brisanje elementov seznama vmesni = zacetek; vozlisce* delovni; for (i=1; i<=10; i++) { cout << vmesni->podatek << endl; delovni=vmesni->k_naslednji; delete vmesni; vmesni = delovni; }; return 0; }