1 00:00:00,000 --> 00:00:02,440 [Powered by Google Translate] [Pointeriai] 2 00:00:02,440 --> 00:00:05,000 [Rob Bowden] [Harvardo universiteto] 3 00:00:05,000 --> 00:00:07,360 [Tai CS50] [CS50.TV] 4 00:00:07,360 --> 00:00:08,820 >> Pakalbėkime apie rodykles. 5 00:00:08,820 --> 00:00:13,710 Iki šiol, mes visada tik dalykų, atminties aiškiai pagal pavadinimą. 6 00:00:13,710 --> 00:00:22,610 Mes sakė, int n = 42, ir tada, kai mes norite naudoti kintamojo n, 7 00:00:22,610 --> 00:00:30,640 mes tik jį vadiname pagal pavadinimą, mes suteikiame jį rašyti kažką panašaus n * 2. 8 00:00:30,640 --> 00:00:34,790 Tačiau, kad kintamasis turi gyventi kažkur atmintyje. 9 00:00:34,790 --> 00:00:37,790 , Kai norite naudoti vertę, kuri šiuo metu yra saugomi viduje n, 10 00:00:37,790 --> 00:00:40,730 arba atnaujinti vertę, n, 11 00:00:40,730 --> 00:00:44,180 jūsų programa turi žinoti, kur atmintyje ieškoti n. 12 00:00:44,180 --> 00:00:48,320 Jei atminties kintamąjį tarnavimo laikas yra vadinamas jo adresas. 13 00:00:48,320 --> 00:00:49,940 Tai kaip namų adresą. 14 00:00:49,940 --> 00:00:53,080 Galiu rasti kažkieno namus, kaip ilgai, kaip aš žinau, savo namų adresą, 15 00:00:53,080 --> 00:00:58,110 ir kompiuterinė programa gali rasti kintamąjį tol, kol ji žino savo atminties adresą. 16 00:00:58,110 --> 00:01:02,660 Rodykles suteikti yra tiesiogiai susijusios su šiomis atminties adresų būdas. 17 00:01:02,660 --> 00:01:06,860 >> C galios daug, kad galėtų manipuliuoti atminties panašaus į tai. 18 00:01:06,860 --> 00:01:09,960 Tačiau su didele galia ateina didelė atsakomybė. 19 00:01:09,960 --> 00:01:14,670 Patarimų gali būti naudojamas pavojingai pakankamai, kad daug programavimo kalbų 20 00:01:14,670 --> 00:01:16,460 paslėpti patarimų visiškai. 21 00:01:16,460 --> 00:01:19,440 Taigi, kodėl C duoti mums patarimų tada? 22 00:01:19,440 --> 00:01:22,680 Kaip žinote, pagal C funkcija argumentai 23 00:01:22,680 --> 00:01:25,370 visada nukopijuoti į funkcijos parametrus. 24 00:01:25,370 --> 00:01:33,260 Taigi, ragindamas kažką panašaus apsikeitimo sandorių dėl kai kurių kintamųjų x ir y 25 00:01:33,260 --> 00:01:38,840 negali kaitalioti x ir y reikšmes į telefono funkcija, 26 00:01:38,840 --> 00:01:40,810 nors tai gali būti naudinga. 27 00:01:40,810 --> 00:01:46,430 Kaip matysime vėliau, perrašyti imtis patarimų apsikeitimo vietose, kuriuos reikia pavertė 28 00:01:46,430 --> 00:01:49,690 leidžia ji paveikti savo Skambintojo kintamuosius. 29 00:01:49,690 --> 00:01:54,150 >> Leiskite eiti per gana paprastas pavyzdys, kokie patarimų galite padaryti. 30 00:01:54,150 --> 00:02:15,550 Tarkime, mes turime int n = 4; ir int * pointer_to_n = & n. 31 00:02:15,550 --> 00:02:18,990 Sustok! Šiek tiek naujos sintaksės padengti. 32 00:02:18,990 --> 00:02:22,600 Pirma, galime interpretuoti & n. 33 00:02:22,600 --> 00:02:27,260 Atminkite, kad viskas atmintyje turi tam tikrą adresą. 34 00:02:27,260 --> 00:02:30,800 Vadinamas "adresas" operatorius Ampersand. 35 00:02:30,800 --> 00:02:36,470 Taigi, ir n nurodo į atminties adresą, kur n yra saugomi. 36 00:02:36,470 --> 00:02:41,560 Dabar, mes saugome šį adresą į naują kintamąjį, pointer_to_n. 37 00:02:41,560 --> 00:02:43,870 Kokia yra šio naujo kintamojo tipas? 38 00:02:43,870 --> 00:02:47,410 Žvaigždutė kintamojo tipo dalis, 39 00:02:47,410 --> 00:02:49,880 ir mes skaityti kaip int * tipo. 40 00:02:49,880 --> 00:02:56,500 Int * reiškia, kad pointer_to_n yra kintamasis, kuris saugo sveikasis skaičius adresą. 41 00:02:56,500 --> 00:03:02,970 Mes žinome, kad ir n yra int *, nes n yra sveikasis skaičius, ir mes n adresą. 42 00:03:02,970 --> 00:03:06,660 Int *, rodyklės tipo pavyzdys. 43 00:03:06,660 --> 00:03:10,150 Kuo greičiau pradėsite matome žvaigždutes tipo, 44 00:03:10,150 --> 00:03:11,950 jūs žinote, kad jūs susiduriame su rodykles. 45 00:03:11,950 --> 00:03:16,520 Kaip ir mes, gali paskelbti kintamąjį kaip int x ir char y, 46 00:03:16,520 --> 00:03:20,410 mes galime pasakyti, int * Z ir char * W. 47 00:03:20,410 --> 00:03:25,190 Int * char * yra tik naujų tipų mums naudoti. 48 00:03:25,190 --> 00:03:29,430 * Vieta gali eiti bet kur prieš kintamojo pavadinimą. 49 00:03:29,430 --> 00:03:34,730 Taigi, tiek int * pointer_to_n - su * Kitas Žiniasklaida, kaip mes turime čia - 50 00:03:34,730 --> 00:03:45,210 ir int * su * šalia pointer_to_n pointer_to_n yra teisingi. 51 00:03:45,210 --> 00:03:56,470 Bet čia, aš įdėti į int * šalia. 52 00:03:56,470 --> 00:04:00,600 Nesvarbu, kuris jums labiau patinka, tiesiog būti nuoseklūs. 53 00:04:00,600 --> 00:04:02,810 >> Leiskite atkreipti šią schemą. 54 00:04:02,810 --> 00:04:07,590 Pirmiausiai mes turime kintamojo n, kurį mes parengti nedidelę dėžutę atminties. 55 00:04:07,590 --> 00:04:15,400 Šiame pavyzdyje, galime pasakyti, kad ši dėžutė yra adresu 100. 56 00:04:15,400 --> 00:04:18,820 Viduje šio langelio, mes saugoti vertę 4. 57 00:04:18,820 --> 00:04:23,730 Dabar, mes turime naują kintamąjį, pointer_to_n. 58 00:04:23,730 --> 00:04:27,030 Jis turi savo langelį atmintyje, 59 00:04:27,030 --> 00:04:32,900 mes pasakyti, yra adresu 200. 60 00:04:32,900 --> 00:04:37,220 Viduje šio langelio, mes saugome n adresą, 61 00:04:37,220 --> 00:04:39,890 kuriuos mes anksčiau sakė, buvo 100. 62 00:04:39,890 --> 00:04:44,710 Dažnai diagramas, pamatysite, tai rodo, kaip pažodiniu rodykle 63 00:04:44,710 --> 00:04:48,730 paliekant pointer_to_n dėžutė, nukreipta į lauką, kuriame saugomi n. 64 00:04:48,730 --> 00:04:54,620 Dabar, ką mes galime iš tikrųjų su pointer_to_n? 65 00:04:54,620 --> 00:05:10,400 Na, jei mes sakome kažką panašaus * pointer_to_n = 8, tai yra skirtingas naudojimas žvaigždutė 66 00:05:10,400 --> 00:05:14,830 , kuri yra visiškai atskirta nuo žvaigždute deklaruojant kintamąjį 67 00:05:14,830 --> 00:05:16,790 rodyklės tipo. 68 00:05:16,790 --> 00:05:21,130 Čia, žvaigždute yra vadinamas operatoriaus dereference. 69 00:05:21,130 --> 00:05:26,860 Mūsų schemoje, * pointer_to_n = 8 priemonė yra 70 00:05:26,860 --> 00:05:32,220 eiti į lauką, kuriame pointer_to_n, atlikite rodyklę, 71 00:05:32,220 --> 00:05:38,160 ir tada priskirti į lauką rodyklės dydis 8 pabaigoje. 72 00:05:38,160 --> 00:05:45,960 Tai reiškia, kad po to, kai šioje eilutėje, jei mes bandome naudoti n turės vertę 8. 73 00:05:45,960 --> 00:05:51,600 Žodis "rodyklė" vartojamas daug skirtinguose kontekstuose. 74 00:05:51,600 --> 00:05:54,380 Čia mes pasistengsime būti nuoseklūs. 75 00:05:54,380 --> 00:05:58,330 Rodyklė tipo kažkas panašaus į int *. 76 00:05:58,330 --> 00:06:04,630 Į šį video rodyklė tik naudojamas vidutinis su rodykle tipo reikšmę, 77 00:06:04,630 --> 00:06:08,180 kaip pointer_to_n, kuris yra tipo int *. 78 00:06:08,180 --> 00:06:15,140 Bet kur mes tiesiog pasakyti, n, mes dabar gali vietoj pasakyti * pointer_to_n, 79 00:06:15,140 --> 00:06:18,020 ir viskas veiks taip pat gerai. 80 00:06:18,020 --> 00:06:21,120 >> Leiskite eiti per kitą paprastą pavyzdį. 81 00:06:21,120 --> 00:06:50,390 Tarkime, mes turime int n = 14; int * rodyklė = nanotechnologijų; n + +, ir (* rodyklė) + +. 82 00:06:50,390 --> 00:06:59,830 Pirmoji eilutė sukuria naują atminties laukelį, pažymėtą n. 83 00:06:59,830 --> 00:07:05,400 Šį kartą, mes ne etiketėje langelį su aiškiu adresu, tačiau jis vis dar yra vienas. 84 00:07:05,400 --> 00:07:11,810 Inside of the box, mes saugoti skaičių 14. 85 00:07:11,810 --> 00:07:22,290 Kitą eilutę sukuria antrą langelį su užrašu žymeklį. 86 00:07:22,290 --> 00:07:27,210 Viduje ir šio langelio, mes laikyti žymeklį į laukelį n. 87 00:07:27,210 --> 00:07:33,170 Taigi, galime atkreipti žymiklį į rodyklę, esančią n. 88 00:07:33,170 --> 00:07:37,790 Dabar, n + + pridės vertės laukelį n, 89 00:07:37,790 --> 00:07:45,420 taip mes einame 14-15. 90 00:07:45,420 --> 00:07:53,330 Galiausiai, (* rodyklė) + + eina į laukelį pavadinimu rodyklė, 91 00:07:53,330 --> 00:08:02,660 dereferences langelyje vertė, o tai reiškia sekti rodyklę, kur jis nurodo, 92 00:08:02,660 --> 00:08:11,690 ir didėja vertė, ten saugomas, todėl mes eiti 15-16. 93 00:08:11,690 --> 00:08:13,480 Ir viskas. 94 00:08:13,480 --> 00:08:18,480 N dabar parduotuvėse, kurios numeris 16, po to, kai padidinamas du kartus - 95 00:08:18,480 --> 00:08:25,050 tiesiogiai per Kintamojo pavadinimas N ir kitas per pointer_to_n. 96 00:08:25,050 --> 00:08:33,360 >> Greita viktorina. Ką jūs manote, kad tai reiškia, jei bandau pasakyti kažką panašaus && n? 97 00:08:33,360 --> 00:08:41,350 Na, galime perrašyti tai & (& n), kuri atlieka tą patį. 98 00:08:41,350 --> 00:08:47,030 (Ir n) grąžina kintamojo n atminties adresą. 99 00:08:47,030 --> 00:08:53,110 Bet tada išorinis Ampersand bando grįžti adreso adresą. 100 00:08:53,110 --> 00:08:56,600 Štai kaip bando daryti ir 2. 101 00:08:56,600 --> 00:09:00,550 Nėra prasmės gauti tik pažymiu adresą 102 00:09:00,550 --> 00:09:03,260 , nes jis nėra saugomas atmintyje. 103 00:09:03,260 --> 00:09:07,090 Naudojant du iš eilės jungimo niekada teisę idėja. 104 00:09:07,090 --> 00:09:28,960 Bet dabar, ką tai reiškia, jei bandau pasakyti, int ** double_pointer = & žymeklį? 105 00:09:28,960 --> 00:09:40,750 Dabar aš sukurti naują langelį su užrašu double_pointer 106 00:09:40,750 --> 00:09:44,590 ir šio langelio viduje aš saugojimo rodyklė adresą 107 00:09:44,590 --> 00:09:50,810 , o tai reiškia, aš atkreipti rodyklę iš double_pointer lange rodyklės laukelį. 108 00:09:50,810 --> 00:09:56,640 Atkreipkite dėmesį double_pointer, int **. 109 00:09:56,640 --> 00:10:03,700 N sveikasis skaičius, rodyklė saugomi n adresas, ir todėl jis turi tipo int *. 110 00:10:03,700 --> 00:10:10,550 Dabar double_pointer saugo rodyklė adresą, todėl jis turi tipas int **. 111 00:10:10,550 --> 00:10:15,070 >> Taigi, ką mes manome, kad tai reiškia - 112 00:10:15,070 --> 00:10:24,490 ** Double_pointer = 23? 113 00:10:24,490 --> 00:10:28,630 Atkreipkite dėmesį, kad aš dabar dereferencing du kartus. 114 00:10:28,630 --> 00:10:32,030 Tiesiog sekite dėžės ir rodyklės schemą, mes jau įsteigti. 115 00:10:32,030 --> 00:10:36,400 Pirmiausia, mes einame į laukelį double_pointer. 116 00:10:36,400 --> 00:10:40,550 * Reiškia, sekti rodyklę kartą. 117 00:10:40,550 --> 00:10:44,110 Dabar mes esame laukelį, pavadintą rodyklė. 118 00:10:44,110 --> 00:10:49,940 Star sako vėl sekti rodyklę, 119 00:10:49,940 --> 00:10:58,230 ir dabar mes tuo laukelį n, ir mes šio langelio vertę 23. 120 00:10:58,230 --> 00:11:05,940 Atkreipkite dėmesį, kad "operatorių dereference ir adresas yra priešingi vienas kitam. 121 00:11:05,940 --> 00:11:16,990 Tai leidžia man padaryti kažką panašaus * & * & n = 42. 122 00:11:16,990 --> 00:11:22,550 Nors tai veikia, jūs niekada neturėtų daryti kažką panašaus į tai praktikoje. 123 00:11:22,550 --> 00:11:24,840 Ką mes iš tikrųjų čia darai? 124 00:11:24,840 --> 00:11:28,700 Pirmas Ampersand griebtuvai kintamojo n adresą. 125 00:11:28,700 --> 00:11:34,660 Tada, mes turime dereference operatorių, o tai reiškia, mes ketiname tuo adresu atmintyje, 126 00:11:34,660 --> 00:11:36,910 todėl mes n. 127 00:11:36,910 --> 00:11:40,910 Dabar mes vėl patraukti n adresą ir iš karto dereference 128 00:11:40,910 --> 00:11:50,780 todėl mes atgal į n ir laikyti 42. 129 00:11:50,780 --> 00:11:55,490 Taigi, kiekvienas * pora ir tiesiog panaikina. 130 00:11:55,490 --> 00:11:59,980 >> Yra speciali rodyklė vadinama null rodyklė. 131 00:11:59,980 --> 00:12:03,140 Tai yra rodyklė, kad mes niekada neturėtų dereference. 132 00:12:03,140 --> 00:12:07,130 Toks žymeklis yra svarbi, nes ji suteikia mums būdas atskirti 133 00:12:07,130 --> 00:12:10,220 žymeklis, kad turėtų ir neturėtų būti dereferenced. 134 00:12:10,220 --> 00:12:13,050 Jei bandysite dereference NULL pointeris, 135 00:12:13,050 --> 00:12:17,150 paprastai jūsų programa bus katastrofos su segmentavimo kaltės, 136 00:12:17,150 --> 00:12:19,210 kurį gali matyti anksčiau. 137 00:12:19,210 --> 00:12:30,490 Taigi, galime sakyti, kad mes kodo, int * x = null; * x = 4. 138 00:12:30,490 --> 00:12:36,190 Šiame pavyzdyje, jis gali atrodyti akivaizdu, kad mes darome kažką blogo, 139 00:12:36,190 --> 00:12:40,650 tačiau nepamirškite, kad null tikrai galėjo būti grąžinta reikšmė nuo skambučio į funkcijos 140 00:12:40,650 --> 00:12:45,930 pavyzdžiui, malloc, jei malloc negali skirti vartotojas prašomą atmintį. 141 00:12:45,930 --> 00:12:50,200 Dėl šios priežasties, jei vietoj x vertę nuo skambučio į malloc 142 00:12:50,200 --> 00:13:12,050 kaip int * x = malloc (sizeof (int)), tada mes turime visada aiškiai patikrinti 143 00:13:12,050 --> 00:13:15,280 pamatyti, jei null buvo grąžintas. 144 00:13:15,280 --> 00:13:43,250 If (x == null) / / uhoh! grįžti; dar galima tęsti ir sakau * x = 4. 145 00:13:43,250 --> 00:13:47,780 >> Taigi, dar kartą, kodėl mes turėtume kada nors naudoti rodykles? 146 00:13:47,780 --> 00:13:51,910 Pažvelkime programos, pavyzdžiui, kur reikia naudoti rodykles - 147 00:13:51,910 --> 00:13:54,110 paprastas apsikeitimo funkcija. 148 00:13:54,110 --> 00:14:08,270 Tarkime, turiu du sveikieji skaičiai, int x = 4; ir int y = 15; 149 00:14:08,270 --> 00:14:21,220 ir aš noriu parašyti funkciją, vadinamą apsikeitimo, kad galiu naudoti, kaip tiek: swap (x, y). 150 00:14:21,220 --> 00:14:28,270 Po šios linijos, viduje kintamojo x reikšmės turi būti 15, 151 00:14:28,270 --> 00:14:32,360 ir viduje kintamojo y reikšmė turėtų būti 4. 152 00:14:32,360 --> 00:14:36,510 Buvo sukeistas viduje x ir y reikšmės. 153 00:14:36,510 --> 00:14:53,040 Be rodykles, mes galime pabandyti kažką panašaus void apsikeitimo sandorio (int, int b); 154 00:14:53,040 --> 00:15:09,750 int tmp = b, b = a; = tmp. 155 00:15:09,750 --> 00:15:12,960 Tačiau, ar jūs pastebėjote, su šia problema? 156 00:15:12,960 --> 00:15:19,000 Atminkite, kad saugomi kintamąjį vertė yra tik x vertės kopija, 157 00:15:19,000 --> 00:15:22,000 ir b reikšmė yra nukopijuotas iš y. 158 00:15:22,000 --> 00:15:28,000 Bet kokie pakeitimai, A ir B nebus atsispindi x ir y. 159 00:15:28,000 --> 00:15:32,050 Taigi, nors A ir B vertės yra teisingai pavertė, 160 00:15:32,050 --> 00:15:35,810 x ir y nepasikeitė ne visiems. 161 00:15:35,810 --> 00:15:38,480 Dabar galime pakeisti swap funkciją, todėl, kad jos argumentai 162 00:15:38,480 --> 00:15:42,180 yra rodykles į kintamuosius, ji turi apsikeitimo, kaip ir: 163 00:15:42,180 --> 00:15:56,880 void apsikeitimo (int *, int * b); int tmp = * b * b = *; * = tmp. 164 00:15:56,880 --> 00:16:00,140 Atminkite, kad, kad apsikeitimo sandoriai argumentai yra dabar patarimų, 165 00:16:00,140 --> 00:16:05,670 todėl reikia perduoti raginimą apsikeitimo, kaip ir X ir Y adresą: 166 00:16:05,670 --> 00:16:15,280 apsikeitimo (ir x, ir y). 167 00:16:15,280 --> 00:16:20,520 Tai dabar teisingai apsikeitimo sandoriai x ir y. 168 00:16:20,520 --> 00:16:24,310 >> Leiskite atkreipti dėžės ir rodyklės diagramą suprasti, kodėl tai veikia. 169 00:16:24,310 --> 00:16:28,520 Mes pradedame nuo mūsų dviejų dėžių atminties, x ir y. 170 00:16:28,520 --> 00:16:35,780 Viduje, X Box yra numeris 4 ir viduje langelyje y turime 15. 171 00:16:35,780 --> 00:16:41,200 Dabar, viduje skambutį į apsikeitimo funkcija, mes turime dvi daugiau langelių 172 00:16:41,200 --> 00:16:45,140 argumentų, a ir b; 173 00:16:45,140 --> 00:16:50,960 taškų už X Box ir b punktų Y už lauke. 174 00:16:50,960 --> 00:16:58,070 Sukurtas naujas langas kintamojo tmp 175 00:16:58,070 --> 00:17:01,470 ir viduje mes saugome dereferencing b, 176 00:17:01,470 --> 00:17:04,980 , kuris reiškia "sekti rodyklę laukelį b." 177 00:17:04,980 --> 00:17:09,880 Taigi, mes saugome 15 TMP viduje. 178 00:17:09,880 --> 00:17:20,560 Tada mes sekti rodyklę b ir laikyti rezultatą dereferencing, 179 00:17:20,560 --> 00:17:24,569 o tai yra vertė 4. 180 00:17:24,569 --> 00:17:35,590 Galiausiai, mes sekti rodyklę A ir parduotuvėje, kas šiuo metu viduje tmp, kuris yra 15. 181 00:17:35,590 --> 00:17:42,440 Atkreipkite dėmesį,, kad langelius su užrašais x ir y teisingai pavertė vertybes. 182 00:17:42,440 --> 00:17:46,290 >> Kai mes sužinoti daugiau apie malloc ir dinaminės atminties valdymo, 183 00:17:46,290 --> 00:17:49,610 mes pamatysime, kad mes neturime kito pasirinkimo, bet naudoti rodykles. 184 00:17:49,610 --> 00:17:52,690 Vaikščioti per dėžutė ir rodyklės schemoje, bet programos 185 00:17:52,690 --> 00:17:55,980 gali padėti jums išsiaiškinti, ką ši programa tikrai daro. 186 00:17:55,980 --> 00:17:59,680 >> My name is Rob Bowden, ir tai yra CS50. 187 00:18:00,000 --> 00:18:02,500 [CS50.TV] 188 00:18:02,500 --> 00:18:06,070 >> Tai yra skirtingas žvaigždute bleah, Aš nekenčiu, kad žodį. 189 00:18:06,070 --> 00:18:13,960 Bet kur mes tiesiog pasakyti, n, mes galime dabar pasakyti pointer_to_n - ne jums Negaliu - * pointer_to_n.