[Powered by Google Translate] [Pointeriai]
[Rob Bowden] [Harvardo universiteto]
[Tai CS50] [CS50.TV]
>> Pakalbėkime apie rodykles.
Iki šiol, mes visada tik dalykų, atminties aiškiai pagal pavadinimą.
Mes sakė, int n = 42, ir tada, kai mes norite naudoti kintamojo n,
mes tik jį vadiname pagal pavadinimą, mes suteikiame jį rašyti kažką panašaus n * 2.
Tačiau, kad kintamasis turi gyventi kažkur atmintyje.
, Kai norite naudoti vertę, kuri šiuo metu yra saugomi viduje n,
arba atnaujinti vertę, n,
jūsų programa turi žinoti, kur atmintyje ieškoti n.
Jei atminties kintamąjį tarnavimo laikas yra vadinamas jo adresas.
Tai kaip namų adresą.
Galiu rasti kažkieno namus, kaip ilgai, kaip aš žinau, savo namų adresą,
ir kompiuterinė programa gali rasti kintamąjį tol, kol ji žino savo atminties adresą.
Rodykles suteikti yra tiesiogiai susijusios su šiomis atminties adresų būdas.
>> C galios daug, kad galėtų manipuliuoti atminties panašaus į tai.
Tačiau su didele galia ateina didelė atsakomybė.
Patarimų gali būti naudojamas pavojingai pakankamai, kad daug programavimo kalbų
paslėpti patarimų visiškai.
Taigi, kodėl C duoti mums patarimų tada?
Kaip žinote, pagal C funkcija argumentai
visada nukopijuoti į funkcijos parametrus.
Taigi, ragindamas kažką panašaus apsikeitimo sandorių dėl kai kurių kintamųjų x ir y
negali kaitalioti x ir y reikšmes į telefono funkcija,
nors tai gali būti naudinga.
Kaip matysime vėliau, perrašyti imtis patarimų apsikeitimo vietose, kuriuos reikia pavertė
leidžia ji paveikti savo Skambintojo kintamuosius.
>> Leiskite eiti per gana paprastas pavyzdys, kokie patarimų galite padaryti.
Tarkime, mes turime int n = 4; ir int * pointer_to_n = & n.
Sustok! Šiek tiek naujos sintaksės padengti.
Pirma, galime interpretuoti & n.
Atminkite, kad viskas atmintyje turi tam tikrą adresą.
Vadinamas "adresas" operatorius Ampersand.
Taigi, ir n nurodo į atminties adresą, kur n yra saugomi.
Dabar, mes saugome šį adresą į naują kintamąjį, pointer_to_n.
Kokia yra šio naujo kintamojo tipas?
Žvaigždutė kintamojo tipo dalis,
ir mes skaityti kaip int * tipo.
Int * reiškia, kad pointer_to_n yra kintamasis, kuris saugo sveikasis skaičius adresą.
Mes žinome, kad ir n yra int *, nes n yra sveikasis skaičius, ir mes n adresą.
Int *, rodyklės tipo pavyzdys.
Kuo greičiau pradėsite matome žvaigždutes tipo,
jūs žinote, kad jūs susiduriame su rodykles.
Kaip ir mes, gali paskelbti kintamąjį kaip int x ir char y,
mes galime pasakyti, int * Z ir char * W.
Int * char * yra tik naujų tipų mums naudoti.
* Vieta gali eiti bet kur prieš kintamojo pavadinimą.
Taigi, tiek int * pointer_to_n - su * Kitas Žiniasklaida, kaip mes turime čia -
ir int * su * šalia pointer_to_n pointer_to_n yra teisingi.
Bet čia, aš įdėti į int * šalia.
Nesvarbu, kuris jums labiau patinka, tiesiog būti nuoseklūs.
>> Leiskite atkreipti šią schemą.
Pirmiausiai mes turime kintamojo n, kurį mes parengti nedidelę dėžutę atminties.
Šiame pavyzdyje, galime pasakyti, kad ši dėžutė yra adresu 100.
Viduje šio langelio, mes saugoti vertę 4.
Dabar, mes turime naują kintamąjį, pointer_to_n.
Jis turi savo langelį atmintyje,
mes pasakyti, yra adresu 200.
Viduje šio langelio, mes saugome n adresą,
kuriuos mes anksčiau sakė, buvo 100.
Dažnai diagramas, pamatysite, tai rodo, kaip pažodiniu rodykle
paliekant pointer_to_n dėžutė, nukreipta į lauką, kuriame saugomi n.
Dabar, ką mes galime iš tikrųjų su pointer_to_n?
Na, jei mes sakome kažką panašaus * pointer_to_n = 8, tai yra skirtingas naudojimas žvaigždutė
, kuri yra visiškai atskirta nuo žvaigždute deklaruojant kintamąjį
rodyklės tipo.
Čia, žvaigždute yra vadinamas operatoriaus dereference.
Mūsų schemoje, * pointer_to_n = 8 priemonė yra
eiti į lauką, kuriame pointer_to_n, atlikite rodyklę,
ir tada priskirti į lauką rodyklės dydis 8 pabaigoje.
Tai reiškia, kad po to, kai šioje eilutėje, jei mes bandome naudoti n turės vertę 8.
Žodis "rodyklė" vartojamas daug skirtinguose kontekstuose.
Čia mes pasistengsime būti nuoseklūs.
Rodyklė tipo kažkas panašaus į int *.
Į šį video rodyklė tik naudojamas vidutinis su rodykle tipo reikšmę,
kaip pointer_to_n, kuris yra tipo int *.
Bet kur mes tiesiog pasakyti, n, mes dabar gali vietoj pasakyti * pointer_to_n,
ir viskas veiks taip pat gerai.
>> Leiskite eiti per kitą paprastą pavyzdį.
Tarkime, mes turime int n = 14; int * rodyklė = nanotechnologijų; n + +, ir (* rodyklė) + +.
Pirmoji eilutė sukuria naują atminties laukelį, pažymėtą n.
Šį kartą, mes ne etiketėje langelį su aiškiu adresu, tačiau jis vis dar yra vienas.
Inside of the box, mes saugoti skaičių 14.
Kitą eilutę sukuria antrą langelį su užrašu žymeklį.
Viduje ir šio langelio, mes laikyti žymeklį į laukelį n.
Taigi, galime atkreipti žymiklį į rodyklę, esančią n.
Dabar, n + + pridės vertės laukelį n,
taip mes einame 14-15.
Galiausiai, (* rodyklė) + + eina į laukelį pavadinimu rodyklė,
dereferences langelyje vertė, o tai reiškia sekti rodyklę, kur jis nurodo,
ir didėja vertė, ten saugomas, todėl mes eiti 15-16.
Ir viskas.
N dabar parduotuvėse, kurios numeris 16, po to, kai padidinamas du kartus -
tiesiogiai per Kintamojo pavadinimas N ir kitas per pointer_to_n.
>> Greita viktorina. Ką jūs manote, kad tai reiškia, jei bandau pasakyti kažką panašaus && n?
Na, galime perrašyti tai & (& n), kuri atlieka tą patį.
(Ir n) grąžina kintamojo n atminties adresą.
Bet tada išorinis Ampersand bando grįžti adreso adresą.
Štai kaip bando daryti ir 2.
Nėra prasmės gauti tik pažymiu adresą
, nes jis nėra saugomas atmintyje.
Naudojant du iš eilės jungimo niekada teisę idėja.
Bet dabar, ką tai reiškia, jei bandau pasakyti, int ** double_pointer = & žymeklį?
Dabar aš sukurti naują langelį su užrašu double_pointer
ir šio langelio viduje aš saugojimo rodyklė adresą
, o tai reiškia, aš atkreipti rodyklę iš double_pointer lange rodyklės laukelį.
Atkreipkite dėmesį double_pointer, int **.
N sveikasis skaičius, rodyklė saugomi n adresas, ir todėl jis turi tipo int *.
Dabar double_pointer saugo rodyklė adresą, todėl jis turi tipas int **.
>> Taigi, ką mes manome, kad tai reiškia -
** Double_pointer = 23?
Atkreipkite dėmesį, kad aš dabar dereferencing du kartus.
Tiesiog sekite dėžės ir rodyklės schemą, mes jau įsteigti.
Pirmiausia, mes einame į laukelį double_pointer.
* Reiškia, sekti rodyklę kartą.
Dabar mes esame laukelį, pavadintą rodyklė.
Star sako vėl sekti rodyklę,
ir dabar mes tuo laukelį n, ir mes šio langelio vertę 23.
Atkreipkite dėmesį, kad "operatorių dereference ir adresas yra priešingi vienas kitam.
Tai leidžia man padaryti kažką panašaus * & * & n = 42.
Nors tai veikia, jūs niekada neturėtų daryti kažką panašaus į tai praktikoje.
Ką mes iš tikrųjų čia darai?
Pirmas Ampersand griebtuvai kintamojo n adresą.
Tada, mes turime dereference operatorių, o tai reiškia, mes ketiname tuo adresu atmintyje,
todėl mes n.
Dabar mes vėl patraukti n adresą ir iš karto dereference
todėl mes atgal į n ir laikyti 42.
Taigi, kiekvienas * pora ir tiesiog panaikina.
>> Yra speciali rodyklė vadinama null rodyklė.
Tai yra rodyklė, kad mes niekada neturėtų dereference.
Toks žymeklis yra svarbi, nes ji suteikia mums būdas atskirti
žymeklis, kad turėtų ir neturėtų būti dereferenced.
Jei bandysite dereference NULL pointeris,
paprastai jūsų programa bus katastrofos su segmentavimo kaltės,
kurį gali matyti anksčiau.
Taigi, galime sakyti, kad mes kodo, int * x = null; * x = 4.
Šiame pavyzdyje, jis gali atrodyti akivaizdu, kad mes darome kažką blogo,
tačiau nepamirškite, kad null tikrai galėjo būti grąžinta reikšmė nuo skambučio į funkcijos
pavyzdžiui, malloc, jei malloc negali skirti vartotojas prašomą atmintį.
Dėl šios priežasties, jei vietoj x vertę nuo skambučio į malloc
kaip int * x = malloc (sizeof (int)), tada mes turime visada aiškiai patikrinti
pamatyti, jei null buvo grąžintas.
If (x == null) / / uhoh! grįžti; dar galima tęsti ir sakau * x = 4.
>> Taigi, dar kartą, kodėl mes turėtume kada nors naudoti rodykles?
Pažvelkime programos, pavyzdžiui, kur reikia naudoti rodykles -
paprastas apsikeitimo funkcija.
Tarkime, turiu du sveikieji skaičiai, int x = 4; ir int y = 15;
ir aš noriu parašyti funkciją, vadinamą apsikeitimo, kad galiu naudoti, kaip tiek: swap (x, y).
Po šios linijos, viduje kintamojo x reikšmės turi būti 15,
ir viduje kintamojo y reikšmė turėtų būti 4.
Buvo sukeistas viduje x ir y reikšmės.
Be rodykles, mes galime pabandyti kažką panašaus void apsikeitimo sandorio (int, int b);
int tmp = b, b = a; = tmp.
Tačiau, ar jūs pastebėjote, su šia problema?
Atminkite, kad saugomi kintamąjį vertė yra tik x vertės kopija,
ir b reikšmė yra nukopijuotas iš y.
Bet kokie pakeitimai, A ir B nebus atsispindi x ir y.
Taigi, nors A ir B vertės yra teisingai pavertė,
x ir y nepasikeitė ne visiems.
Dabar galime pakeisti swap funkciją, todėl, kad jos argumentai
yra rodykles į kintamuosius, ji turi apsikeitimo, kaip ir:
void apsikeitimo (int *, int * b); int tmp = * b * b = *; * = tmp.
Atminkite, kad, kad apsikeitimo sandoriai argumentai yra dabar patarimų,
todėl reikia perduoti raginimą apsikeitimo, kaip ir X ir Y adresą:
apsikeitimo (ir x, ir y).
Tai dabar teisingai apsikeitimo sandoriai x ir y.
>> Leiskite atkreipti dėžės ir rodyklės diagramą suprasti, kodėl tai veikia.
Mes pradedame nuo mūsų dviejų dėžių atminties, x ir y.
Viduje, X Box yra numeris 4 ir viduje langelyje y turime 15.
Dabar, viduje skambutį į apsikeitimo funkcija, mes turime dvi daugiau langelių
argumentų, a ir b;
taškų už X Box ir b punktų Y už lauke.
Sukurtas naujas langas kintamojo tmp
ir viduje mes saugome dereferencing b,
, kuris reiškia "sekti rodyklę laukelį b."
Taigi, mes saugome 15 TMP viduje.
Tada mes sekti rodyklę b ir laikyti rezultatą dereferencing,
o tai yra vertė 4.
Galiausiai, mes sekti rodyklę A ir parduotuvėje, kas šiuo metu viduje tmp, kuris yra 15.
Atkreipkite dėmesį,, kad langelius su užrašais x ir y teisingai pavertė vertybes.
>> Kai mes sužinoti daugiau apie malloc ir dinaminės atminties valdymo,
mes pamatysime, kad mes neturime kito pasirinkimo, bet naudoti rodykles.
Vaikščioti per dėžutė ir rodyklės schemoje, bet programos
gali padėti jums išsiaiškinti, ką ši programa tikrai daro.
>> My name is Rob Bowden, ir tai yra CS50.
[CS50.TV]
>> Tai yra skirtingas žvaigždute bleah, Aš nekenčiu, kad žodį.
Bet kur mes tiesiog pasakyti, n, mes galime dabar pasakyti pointer_to_n - ne jums Negaliu - * pointer_to_n.