[Powered by Google Translate] [Ukazovatele]
[Rob Bowden] [Harvard University]
[To je CS50] [CS50.TV]
>> Poďme hovoriť o ukazovatele.
Až do teraz, sme vždy len odvolával sa na veci v pamäti explicitne podľa názvu.
Povedali sme int n = 42, a potom, keď chceme použiť premennú n,
sme len zavolať ju menom dáme ju písať niečo ako n * 2.
Ale že premenná musí žiť niekde v pamäti.
Ak chcete použiť hodnotu, ktorá je v súčasnosti uložená v n,
alebo aktualizovať hodnotu, ktorá n je drží,
váš program potrebuje vedieť, kde v pamäti hľadať pre n
Ak v pamäti je premenná žije volal jeho adresu.
Je to ako dom adresu.
Nemôžem nájsť niečí dom tak dlho, ako viem, svoju adresu,
a počítačový program môžete nájsť premennú tak dlho, ako to pozná jeho adresu v pamäti.
Čo ukazovatele poskytujú, je spôsob, ako priamo sa zaoberať týmito pamäťovými adresami.
>> Veľa energie v C pochádza z byť schopný manipulovať pamäte, ako je tento.
Ale s veľkou mocou prichádza aj veľká zodpovednosť.
Ukazovatele môžu byť použité nebezpečne natoľko, že mnoho programovacích jazykov
skryť ukazovatele úplne.
Tak, prečo C nám odkazy potom?
Ako viete, argumenty funkcie C
sú vždy skopírovaná do parametrov funkcie.
Takže, volať niečo ako odkladací priestor na niektorých premenných x a y
nemôže striedať hodnoty X a Y v volajúci funkciu,
aj keď to môže byť užitočné.
Ako uvidíme neskôr, prepisovanie odkladacia aby ukazovatele na umiestnenie, ktoré je potrebné vymeniť
umožňuje ovplyvniť jeho návštevníkovi je premenné.
>> Poďme prejsť pomerne priamočiare príklad toho, čo môže urobiť ukazovatele.
Povedzme, že máme int n = 4, a int * pointer_to_n = & n
Whoa! Trochu novú syntax na krytie.
Po prvé, poďme to vyložiť & n
Pamätajte si, že všetko, čo v pamäti má nejakú adresu.
Ampersand sa nazýva "adresa" subjektu.
Takže, & n odkazuje na adresu v pamäti, kde je uložený n
Teraz sa ukladajú túto adresu do novej premennej, pointer_to_n.
Aký je typ tejto novej premennej?
Hviezdička je súčasťou typu premennej,
a budeme čítať ako typ int *.
Int * znamená, že pointer_to_n je premenná, ktorá ukladá adresu integer.
Vieme, že a n je int * od n je celé číslo, a my sme sa ujali adresu n.
Int * je príklad typ ukazovateľa.
Akonáhle začnete vidieť Hviezdičky v typu,
viete, že máte čo do činenia s ukazovateľmi.
Rovnako ako môžeme deklarovať premennú ako int x a y, char
môžeme povedať, int * Z a char * w.
Int * a char * sú len nové typy pre nás používať.
Umiestnenie * môže ísť kamkoľvek pred názvom premennej.
Takže, ako int * pointer_to_n - s * vedľa int, ako sme tu -
a int * pointer_to_n s * vedľa pointer_to_n sú platné.
Ale tu, budem umiestnite * vedľa int.
Nezáleží na tom, ktoré dávate prednosť, jednoducho byť v súlade.
>> Poďme nakresliť schému pre tento.
Musíme najprv premennú n, ktoré budeme čerpať ako krabičke pamäte.
Pre tento príklad, povedzme, že toto políčko je umiestnená na adrese 100.
Vnútri tohto poľa, sme uloženie hodnotu 4.
Teraz máme novú premennú, pointer_to_n.
Má svoj vlastný box v pamäti,
ktoré budeme hovoriť, je na adrese 200.
Vnútri tohto poľa, sme ukladanie adresu n,
ktoré sme predtým hovorili bolo 100.
Často na obrázkoch, uvidíte to ukáže ako doslovný šípky
opúšťať pointer_to_n box ukazuje na pole, ktoré ukladá n
Teraz, čo môžeme skutočne urobiť s pointer_to_n?
No, keď povieme niečo ako * pointer_to_n = 8, to je iná použitie pre hviezdička
že je úplne oddelená od použitia hviezdičkou v deklarovaní premennej
o ukazovatele typu.
Tu, hviezdička je nazýva dereferencia operátor.
V našom diagrame, čo * pointer_to_n = 8 znamená,
prejsť na pole obsahujúce pointer_to_n, za šípkou,
a potom priradiť pole na konci šípky hodnota 8.
To znamená, že po tejto línie, ak sa pokúsi použiť n, že bude mať hodnotu 8.
Slovo "ukazovateľ" sa používa v mnohých rôznych kontextoch.
Tu sa budeme snažiť byť v súlade.
Ukazovateľ typu je niečo ako int *.
V tomto videu, bude ukazovateľ byť použité iba pre vyjadrenie hodnoty s typ ukazovateľa,
ako pointer_to_n ktorá má typ int *.
Kdekoľvek sme len povedať n, môžeme sa teraz namiesto povedať * pointer_to_n,
a všetko bude fungovať rovnako dobre.
>> Prejdime ďalšie jednoduchý príklad.
Povedzme, že máme int n = 14; int * ukazovateľ = &n; n + +, a (* ukazovateľ) + +.
Prvý riadok vytvorí nový rámik v pamäti označené n
Tentoraz nebudeme označiť políčko s výslovným adresou, ale stále má jeden.
Vnútri krabice, sme uloženie čísla 14.
Na ďalší riadok vytvorí druhý políčko ukazovateľ.
A vo vnútri tohto poľa, sme uloženie ukazovateľ na pole s označením n
Takže, poďme nakreslite šípku z ukazovateľa na n
Teraz, n + + inkrementuje hodnotu v poli označenom n,
tak ideme 14-15.
Konečne, (* ukazovateľ) + + ide do krabice označenej ukazovatele,
dereferences hodnota v poli, čo znamená, že za šípkou na miesto, kde sa uvádza,
a zvyšuje sa hodnota uloží tam, tak ideme 15-16.
A to je všetko.
N teraz ukladá počet 16 potom, čo bol zvýšený dvakrát -
raz priamo pomocou názvu premennej n, a druhá cez pointer_to_n.
>> Rýchly kvíz. Čo si myslíte, že to znamená, keď sa snažím povedať niečo ako && n?
Dobre, poďme prepísať toto ako a (a n), ktorý vykoná rovnakú vec.
The (a n) vracia adresu premennej N v pamäti.
Ale potom kliknite na vonkajšie ampersand snaží vrátiť adresu adresy.
To je ako snažiť sa robiť a 2.
To nedáva zmysel získať adresu iba nejakým číslom
pretože to nie sú uložené v pamäti.
Pomocou dvoch Ampersand v rade nie je nikdy správna myšlienka.
Ale teraz, čo to znamená, keď sa snažím povedať, int ** double_pointer = & ukazovateľ?
Teraz som vytvoriť novú políčko double_pointer,
a vo vnútri tej krabice som ukladanie adresu ukazovatele,
čo znamená, že nakresliť šípku z krabice double_pointer na ukazovateľ poľa.
Všimnite si, že typ double_pointer, int **.
N bol integer, ukazovateľ uložený adresu n, a tak to má typ int *.
Teraz, double_pointer ukladá adresu ukazovateľ, tak to má typ int **.
>> Takže, čo si myslíme, že to znamená -
** Double_pointer = 23?
Všimnite si, že som teraz dereferencing dvakrát.
Stačí sledovať box a šípkou diagram sme už nastavili.
Po prvé, sme sa ísť do poľa označeného double_pointer.
Prvý * znamená nasledovať raz šípku.
Teraz sme v pokladni označené ukazovateľom.
Druhá hviezda hovorí, že nasledovať šípku znovu,
a teraz sme na poli označenom n, a nastavíme hodnotu tohto poľa 23.
Všimnite si, že dereferencia a "adresa" operátorov sú inverses navzájom.
To mi umožňuje urobiť niečo ako * & * & n = 42.
Kým to funguje, mali by ste sa nikdy niečo také v praxi.
Čo sme vlastne tu?
Prvý ampersand chytí adresu premennej n
Potom máme dereferencia operátor, čo znamená, že sa budeme na túto adresu v pamäti,
takže sme zase na n
Teraz uchopiť adresu n znovu a okamžite dereferencia,
Takže sme späť u n a sklad 42.
Takže, každý pár * a len ruší.
>> K dispozícii je špeciálny ukazovateľ nazvaný nulový ukazovateľ.
To je ukazovateľ, ktorý by sme mali nikdy dereferencia.
Takýto ukazovateľ je dôležitý, pretože nám dáva spôsob, ako rozlišovať medzi
ukazovateľ, ktorý by mal a nemal byť dereferenced.
Ak sa pokúsite dereferencia ukazovatele null,
obvykle váš program spadne s Segmentation fault,
ktoré ste možno nevideli.
Takže, povedzme, že máme kód int * x = null; * x = 4.
V tomto príklade, sa môže zdať zrejmé, že robíme niečo zlé,
ale nezabudnite, že null môže byť skutočne hodnota vrátená z volania funkcie
ako malloc, ak malloc nie je schopný prideliť pamäť požadované užívateľom.
Z tohto dôvodu sa v prípade namiesto toho nastaviť hodnotu x z volania malloc,
ako v int * x = malloc (sizeof (int)), potom by sme mali vždy explicitne kontrolovať
či null bol vrátený.
If (x == null); / / UHOH! return; ešte môžeme pokračovať ďalej a hovoriť * x = 4.
>> Takže znova, prečo by sme mali vždy používať ukazovatele?
Poďme sa pozrieť na príklad programu, kde musíme používať ukazovatele -
jednoduchá výmena funkcií.
Povedzme, že mám dve celé čísla, int x = 4, a int y = 15;
a chcem napísať funkciu nazvanú swap, ktorý môžem použiť ako tak: odkladacie (x, y).
Po tejto línie, mali by sa hodnoty v rámci premennej x je 15,
a hodnota v premennej y mal byť 4.
Hodnoty vnútorná časť x a y boli vymenené.
Bez ukazovatele, môžeme skúsiť niečo ako void swapu (int, int b);
int tmp = b, b =; = tmp.
Ale, to si všimnete problém s tým?
Nezabudnite, že hodnota uložená v premennej je len kópia hodnoty x,
a hodnota vb je skopírovaný z y.
Všetky zmeny vykonané v a a b sa neprejaví v x a y.
Takže, zatiaľ čo hodnoty a a b sú správne prehodenie,
x a y sa vôbec nezmenila.
Teraz, poďme zmeniť odkladacie funkciu tak, že jej argumenty
sú ukazovatele na premenné treba swapového, ako tak:
void swap (int *, int * b); int tmp = * b; * b = *, * = tmp.
Pamätajte si, že swapy argumenty sú teraz ukazovatele,
a tak musíme odovzdať adresu x a y vo výzve k výmene, ako tak:
swap (a x, a y).
Toto teraz správne swapy sú hodnoty x a y.
>> Poďme nakresliť box-and-šípky diagramu vidieť prečo to funguje.
Začneme s našimi dvoma boxy v pamäti, X a Y.
Vnútri boxu pre x je číslo 4, a vo vnútri boxu pre y máme 15.
Teraz, vo vnútri volania do swapu funkcie, máme dve ďalšie krabice
pre argumenty a a b;
a poukazuje na pole pre x, a, b ukazuje na pole pre y.
Nový box je vytvorený pre premenné tmp,
a vo vnútri nej uložíme výsledok dereferencing b,
čo znamená, že "za šípkou z krabice označenej b"
Takže, uložíme 15 vnútri tmp.
Potom sledujeme na šípku b a uložiť tu výsledok dereferencing,
čo je hodnota 4.
Konečne, sledujeme na šípku v obchode a čo je v súčasnej dobe vo vnútri tmp, ktoré je 15 rokov.
Všimnite si, že tieto boxy označené x a y správne vymenili hodnoty.
>> Akonáhle sa dozvieme viac o malloc a dynamickú správu pamäte,
uvidíme, že nemáme inú možnosť, než použiť ukazovatele.
Prechádzky box-a-šípka diagramu pre každý program
vám môže pomôcť zistiť, čo program skutočne robí.
>> Moje meno je Rob Bowden, a to je CS50.
[CS50.TV]
>> To je iná použitie pre hviezdičku - bleah, neznášam to slovo.
Kdekoľvek sme len povedať n, môžeme teraz povedať, pointer_to_n - no ty nemôžeš - * pointer_to_n.