[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.