[Powered by Google Translate] [Mutatók]
[Rob Bowden] [Harvard Egyetem]
[Ez CS50] [CS50.TV]
>> Beszéljünk mutatók.
Eddig mi mindig imént említett dolgok a memóriában kifejezetten név szerint.
Már mondtam int n = 42, és akkor, amikor akarjuk használni a változó n,
hívjuk azt a nevet adjuk, hogy írásban valami ilyesmi n * 2.
De ez változót kell élni valahol a memóriában.
Ha szeretné használni az érték jelenleg tárolt n,
vagy frissíteni az az érték, n birtok,
A programnak tudnia kell, hol a memóriában keresni n.
Ha a memóriában a változó életet nevezzük annak címét.
Ez olyan, mint egy ház címet.
Találok valakit házába, amíg tudom, hogy a lakcím,
és egy számítógépes program talál egy változó, amíg tudja a memória címét.
Milyen mutatók nyújtanak egy módja, hogy közvetlenül foglalkozik ezekkel a memória címeket.
>> Sok a hatalom C származik, hogy képes manipulálni memóriát, mint ez.
De a nagy hatalommal nagy felelősség jár.
Mutatók lehet használni veszélyesen ahhoz, hogy egy csomó programozási nyelvek
elrejteni mutatók teljesen.
Szóval, miért C nekünk mutató akkor?
Mint tudod, érveket a C függvény
mindig másolja a paramétereket a funkciót.
Szóval, amelyben valami ilyesmit swap bizonyos változók x és y
nem tudja cserélje fel az az x és y a hívó funkció,
annak ellenére, hogy lehet, hogy praktikus.
Mint látni fogjuk később, újraírás csere, hogy rámutatnak a helyekre kelljen cserélték
lehetővé teszi, hogy befolyásolja a hívó változók.
>> Sétáljunk egy viszonylag egyszerű példa arra, mi mutatók tehet.
Tegyük fel, hogy van int n = 4, és int * pointer_to_n = & n.
Hűha! Egy kicsit az új szintaxis fedezni.
Először is, hadd értelmezi ezt a & n.
Ne feledje, hogy minden a memóriában van néhány címet.
A jel az úgynevezett "címe" operátor.
Így, & n utal a cím memóriában ahol n tárolják.
Most tárolja ezt a címet egy új változó, pointer_to_n.
Milyen típusú az új változó?
A csillag része a változó típusát,
és mi olvasni a típus int *.
Int * azt jelenti, hogy pointer_to_n olyan változó, amely tárolja a címét egy egész.
Tudjuk, hogy a & n int * mivel n egész szám, és mi figyelembe a címét n.
Int * egy példa egy mutató típus.
Amint elkezdi látni csillagokat a típusát,
tudod, hogy dolgunk mutatók.
Csakúgy, mint mi is, hogy egy változót, mint int x és y char,
azt mondhatjuk, int * z és char * w.
Int * és char * csak új típusú nekünk használni.
A helyszín a * mehet sehova, mielőtt a változó nevét.
Tehát mindkét int * pointer_to_n - a * mellett int, hiszen van itt -
és int * pointer_to_n a * mellett pointer_to_n érvényesek.
De itt, én helyezze a * mellett int.
Nem számít, amely szeretné, csak legyen következetes.
>> Nézzünk felhívni a diagram erre.
Először is a változó n, amit akkor döntetlen, mint egy kis doboz a memória.
Ebben a példában, mondjuk, hogy ez a rovat található címen 100.
Belül ezt a rovatot, mi tárolása érték 4.
Most van egy új változót, pointer_to_n.
Megvan a saját mezőbe a memóriában,
amit majd mondani címen 200.
Belül ezt a rovatot, mi tárolása címét n,
amelyhez előtt azt mondta, hogy 100-zal.
Gyakran a diagramok, látni fogod, ezt mutatja, mint egy szó nyíl
elhagyó pointer_to_n dobozt mutat a doboz, amely tárolja n.
Nos, mit tudunk valójában csinálni pointer_to_n?
Nos, ha azt mondjuk, hogy valami hasonlót * pointer_to_n = 8, ez egy másik alkalmazása a csillag
amely teljesen elkülönül a használata a csillag nyilvánító változó
Egy pointer típusú.
Itt a csillagot nevezzük dereference operátor.
A mi diagram, amit * pointer_to_n = 8 azt jelenti,
megy a dobozban pointer_to_n kövesse a nyilat,
és utána hozzárendeli a végén lévő bekeretezett a nyíl a 8-at.
Ez azt jelenti, hogy miután ezt a sort, ha megpróbáljuk használni n ez lesz az érték 8.
A "pointer" kifejezés sok különböző helyzetekben.
Itt megpróbáljuk lenniük.
A mutató típus valami ilyesmi int *.
Ebben a videóban a mutató csak akkor használható olyan érték egy mutató típusú,
mint pointer_to_n amelynek típusa int *.
Bárhol szoktuk mondjuk n, most már inkább azt mondják * pointer_to_n,
és minden működik ugyanúgy.
>> Sétáljunk egy másik egyszerű példát.
Tegyük fel, hogy van int n = 14; int * pointer = &n; n + +, és (* pointer) + +.
Az első sor létrehoz egy új rovat a memória feliratú n.
Ezúttal nem címkézik a dobozt egy explicit címet, de még mindig van egy.
Belül a doboz, mi tárolja a számot 14.
A következő sorban létrehoz egy második doboz feliratú mutató.
És belül ezt a rovatot, mi tárolása mutatót a mezőbe n.
Szóval, most felhívni a nyilat mutató n.
Most, n + + lépésenként az értéket a mezőbe n,
így megy 14-15.
Végül a (* pointer) + + megy a mezőbe mutató,
dereferences az értéket a mezőbe, ami azt jelenti, kövesse a nyilat, ahol megjegyzi,
és növeli az értéket az ott tárolt, így megy 15-16.
És ennyi.
N most tárolja a 16 szám, miután kétszer is növekszik -
egyszer közvetlenül a változó nevét N, és a másik egy pointer_to_n.
>> Gyors kvíz. Mit gondolsz, ez azt jelenti, ha megpróbálok mondani valamit, mint && n?
Nos, akkor átírják ezt és (& n), amely megvalósítja az ugyanaz a dolog.
A (+ n) visszaadja a címét n változó a memóriában.
De akkor aztán külső jelet próbál visszatérni a cím a címet.
Ez olyan, mintha próbálkozik és 2.
Ennek semmi értelme, hogy a címét csak néhány szám
mivel ez nem tárolja a memóriában.
Két ampersands egy sorban soha nem egy jó ötlet.
De most, mit jelent az, ha megpróbálom elmondani int ** double_pointer = & pointer?
Most hozok létre egy új feliratú mezőben double_pointer,
és belső e rovat vagyok tárolása címét mutató,
ami azt jelenti, hogy dolgozzon egy nyilat a double_pointer mezőben a mutató mezőben.
Figyeljük meg, hogy milyen típusú double_pointer, int **.
N volt egy egész szám, mutató tárolt a címét, N, és így azt, típus int *.
Most double_pointer tárolja címe mutató, így azt írja int **.
>> Szóval, mit gondolunk ez azt jelenti -
** Double_pointer = 23?
Figyeljük meg, hogy én vagyok most dereferencing kétszer.
Csak kövesse a doboz-és nyíl diagram mi már létrehozott.
Először megyünk a mezőbe double_pointer.
* Az első azt jelenti, kövesse a nyilat egyszer.
Most vagyunk a mezőbe mutatót.
A második csillag azt mondja, kövesse a nyilat újra,
és most mi vagyunk a mezőbe n, és állítsa az értékét doboz 23.
Figyeljük meg, hogy a dereference és "címe" piaci szereplők inverze egymásnak.
Ez lehetővé teszi, hogy tegyek valamit, mint a * & * & n = 42.
Bár ez működik, akkor soha nem valami ilyesmi a gyakorlatban.
Mit keresünk valójában csinál itt?
Az első jel megragadja a címe a változó n.
Aztán van egy dereference operátor, ami azt jelenti, fogunk ezt a címet a memóriában,
Szóval vissza n.
Most fogd a címét n újra és azonnal dereference,
Szóval vissza n és tárolja 42.
Szóval, egy pár * és csak kioltja.
>> Van egy speciális mutató úgynevezett null mutató.
Ez egy olyan mutató, amit soha ne dereference.
Egy ilyen mutató azért fontos, mert ez ad nekünk egy lehet megkülönböztetni között
a mutató, hogy az kell, és nem kell másolunk.
Ha megpróbálod dereference egy null pointer,
általában a program összeomlik egy szegmentációs hiba,
ami lehet, hogy látott.
Tehát, mondjuk mi a kód int * x = null; * x = 4.
Ebben a példában, úgy tűnhet, nyilvánvaló, hogy csinálunk valami rossz,
de ne feledje, hogy null tényleg egy visszaadott érték hívás funkció
mint malloc, ha malloc nem tudott memóriát a memória a felhasználó által kért.
Emiatt, ha ehelyett az értéket az x egy hívás malloc,
mint az int * x = malloc (sizeof (int)), akkor mindig kifejezetten megtekintéséhez
hogy ha null-ben tért vissza.
Ha az (x == null) / / uhoh! vissza; mást tudunk folytatni, és azt mondják * x = 4.
>> Szóval, megint, miért kellene valaha is használni mutatók?
Nézzünk egy példát a program, ahol meg kell használni mutatók -
egy egyszerű csere funkciót.
Tegyük fel, hogy van két egész, int x = 4, és int y = 15;
és azt akarom, hogy írjon egy függvényt nevű csereügylet, hogy tudom használni valahogy így: swap (x, y).
Ezután ezt a sort, az értékeket belsejét az x változó legyen 15,
és az érték belül változó y kell 4.
Az értékek belső x és y is cserélni.
Nélkül mutatók, talán próbálj ki valami ilyesmit void swap (int a, int b);
int tmp = b, b = a, a = tmp.
De nem azt veszi észre, a probléma ezzel?
Vegye figyelembe, hogy a tárolt érték a változó egy csak egy másolata az x értéke,
és az értéket ab másolt y.
Minden változtatás történt a és b nem tükröződik x és y.
Így, míg a értékei a és b helyesen cserélve,
X és Y nem változott.
Most változtassuk meg a csere funkciót annak érdekében, hogy érveit
olyan mutatókat változók kell cserélni, valahogy így:
void swap (int * a, int * b); int tmp = * b, * b = a *, * a = tmp.
Ne feledje, hogy a swap érvek most mutatók,
és ezért meg kell adni a címét, x és y a hívás csere, valahogy így:
csere (& x, & y).
Ez most helyesen swap a az x és y.
>> Nézzünk rajzoljon egy doboz-és nyíl diagram belátni, hogy miért is működik ez.
Kezdjük a két doboz a memóriában, x és y.
Belül a doboz x az a szám, 4, és azon belül a doboz y van 15.
Most, belsejében a hívás a swap függvény, van még két doboz
Az érvek a és b;
Egy pont a doboz x és b rámutat a doboz y.
Egy új doboz jön létre a változó tmp,
és belsejében tároljuk eredménye dereferencing b,
ami azt jelenti, "követi a nyilat a jelölőnégyzetet b."
Szóval, mi tároljuk 15 belül tmp.
Ezután követjük a nyílra b és tárolja itt az eredménye dereferencing a,
amely az érték 4.
Végül kövesse a nyíl, és egy boltban, mi van jelenleg a belsejében tmp, amely 15.
Figyeljük meg, hogy a dobozok jelzett X és Y jelentése helyesen cseréltek értékeket.
>> Amint többet megtudni a malloc és dinamikus memória kezelése,
látni fogjuk, hogy nincs más választásunk, mint hogy mutatók.
Séta a doboz-és nyíl diagram minden program
segít kitalálni, hogy mi a program valóban csinál.
>> A nevem Rob Bowden, és ez CS50.
[CS50.TV]
>> Ez egy másik alkalmazása a csillag - bleah, utálom ezt a szót.
Bárhol szoktuk mondjuk n, most már mondjuk pointer_to_n - nem te Nem látom - * pointer_to_n.