[Powered by Google Translate] [Pokazivači] [Rob Bowden] [Sveučilište Harvard] [Ovo je CS50] [CS50.TV] Ajmo pričati o pokazivače. Do sada, uvijek smo se samo spominju stvari u memoriji izričito po imenu. Mi smo govorili int n = 42, a onda kada želimo koristiti varijablu n, samo smo ga nazvati po imenu mi ga dati pišući nešto poput N * 2. No, da varijabla mora živjeti negdje u memoriji. Kada želite koristiti vrijednost koja je trenutno pohranjene unutar n, ili ažurirati vrijednost koja je n holding, Vaš program treba da znaju gdje se u memoriji tražiti n. Gdje u memoriji varijabilni živi se zove njegova adresa. To je kao kuća adresu. Ja mogu pronaći nečiju kuću dok ja znam svoju kućnu adresu, i računalni program može pronaći varijablu dok ona zna svoju memorijsku adresu. Što upućuje pružiti je način izravno bave ovim memorijskim adresama. Puno snage u C dolazi od toga da bude u mogućnosti da manipuliraju memoriju ovako. No, s velikom moći dolazi i velika odgovornost. Pokazivači se mogu koristiti opasno dovoljno da puno programskim jezicima sakriti naputke u cijelosti. Dakle, zašto ne C nam dati naputke onda? Kao što znate, argumenti u funkciji C uvijek kopirati u parametrima funkcije. Dakle, nazivajući nešto poput swapa na nekim varijablama x i y Ne mogu smjenjivati ​​vrijednosti xiy u pozivate funkciju, iako bi moglo biti pri ruci. Kao što ćemo kasnije vidjeti, ponovno zamjena da se upućuje na lokacijama koje trebaju biti zamijeniti omogućuje da utječu na njegovo pozivatelja varijable. Idemo prošetati kroz relativno jednostavan primjer onoga što upućuje može učiniti. Recimo imamo int n = 4, a int * pointer_to_n = & n. Opa! Malo novom sintaksom za pokriće. Prvo, hajdemo to tumači & n. Sjetite se da je sve u memoriji ima neku adresu. Je pečatni znak se zove "adresa" operatera. Dakle, & n odnosi na adresu u memoriji, gdje je n je pohranjena. Sada, mi smo skladištenje ovu adresu u novom varijablom, pointer_to_n. Što je vrsta ovog novog varijable? Zvjezdica je dio varijable tipa, a mi ćemo čitati tip kao int *. Interesi * znači da pointer_to_n je varijabla koja pohranjuje adrese cijeli broj. Mi znamo da i n int * jer je n cijeli broj, a mi smo uzimanje adresu n. Interesi * je primjer tipa pokazivača. Čim početi dobivati ​​zvijezdicama u vrsti, znate da ste se bave s pokazivačima. Baš kao što možemo proglasiti varijablu kao int x, y, char možemo reći int * z i char * w. Interesi * i char * su samo nove vrste za nas koristiti. Položaj * može ići nigdje prije imena varijable. Dakle, kako int * pointer_to_n - s * uz int, kao što smo ovdje - i int * pointer_to_n s * uz pointer_to_n vrijede. Ali ovdje, ja ću staviti * pored Int. To ne smeta što vam je draže, samo biti dosljedan. Ajmo nacrtati dijagram za to. Mi prvo moramo varijablu n, koje ćemo izvući kao mala kutija memorije. Za ovaj primjer, recimo da je to kutija se nalazi na adresi 100. Unutar tog okvira, mi smo pohranu vrijednost 4. Sada imamo novu varijablu, pointer_to_n. Ona ima svoj vlastiti okvir u memoriju, što ćemo reći da je na adresi 200. Unutar tog okvira, mi smo pohranu adresu n, koje smo prije rekao je 100. Često se u dijagramima, vidjet ćete to pokazalo kao doslovnom strelice ostavljajući pointer_to_n okvir pokazujući na okvir koji pohranjuje n. Sada, ono što možemo zapravo učiniti s pointer_to_n? Pa, ako ćemo reći nešto poput * pointer_to_n = 8, ovo je drugačiji korištenje za Zvjezdica koja je potpuno odvojen od korištenja zvjezdicom u izjavi varijablu od tipa pokazivača. Evo, zvjezdicu se zove dereference operater. U našoj shemi, što * pointer_to_n = 8 znači, ići na box sadrži pointer_to_n, slijedite strelicu, a zatim dodijeliti okvir na kraju strelice vrijednost 8. To znači da će nakon ove linije, ako ćemo pokušati iskoristiti n to će imati vrijednost 8. Riječ 'pokazivač' se koristi u puno različitim kontekstima. Evo, pokušat ćemo biti dosljedni. Pokazivač tip je nešto poput int *. U ovom videu, pokazivač će se koristiti samo znači vrijednost s ciljnikom tipa, kao pointer_to_n koji ima * Tip int. Bilo gdje smo se samo reći n, sada možemo reći umjesto * pointer_to_n, i sve će raditi jednako dobro. Idemo prošetati kroz drugi jednostavnom primjeru. Recimo imamo int n = 14; int * pokazivač = &n; n + +, a (* pokazivač) + +. Prva linija stvara novi okvir u memoriji oznakom n. Ovaj put, nećemo označiti okvir s eksplicitnim adresu, ali još uvijek ima jedan. Unutar okvira, mi smo pohranu broj 14. U sljedećem retku stvara drugi okvir označen pokazivač. A unutar tog okvira, mi smo pohranu pokazivač na okvir s oznakom n. Dakle, neka je privući strelicu pokazivača na n. Sada, n + + koracima vrijednost u kutiji s natpisom n pa idemo 14-15. Konačno, (* pokazivač) + + ide na box oznakom pokazivač, dereferences vrijednost u okvir, što znači slijediti strelicu na kojem ukazuje, i povećava vrijednost pohranjena tamo, pa idemo 15-16. I to je to. N sada pohranjuje broj 16, nakon što je porastao dva puta - jednom izravno pomoću ime varijable n, a drugi kroz pointer_to_n. Brzi kviz. Što mislite to znači ako ja pokušati reći nešto poput && n? Pa, neka je prepisati to kao i (& n) koja ostvaruje istu stvar. The (& n) vraća adresu varijable n u sjećanju. Ali onda onda vanjski znak za struju pokušava vratiti adresu adresu. To je kao da pokušavate napraviti i dva. To nema smisla da biste dobili adresu samo neki broj jer nije se pohranjuju u memoriju. Korištenje dva znakove za redom nikada nije pravo ideja. Ali sada, što to znači, ako sam pokušati reći int ** double_pointer = & pokazivač? Sada, ja sam stvara novi okvir označen double_pointer, i unutar tog okvira sam pohranu adresu pokazivača, što znači da sam nacrtati strelicu iz double_pointer kutije s ciljnikom kutiji. Obavijest vrstu double_pointer, int **. N je broj, pokazivač pohranjena adresa n, i tako to ima * Tip int. Sada, double_pointer pohranjuje adresu pokazivača, tako da ima tip int **. Dakle, ono što mi mislimo to znači - ** Double_pointer = 23? Primijetit ćete da ja sam sada dereferencing dvaput. Samo slijedite kutija i strelice dijagram već smo postavili. Prvo, idemo na označenom double_pointer. Prvi * znači slijediti strelicu jednom. Sada, mi smo na box označen pokazivača. Druga zvijezda kaže slijediti strelicu opet, i sad smo na označenom n, a postavili smo vrijednost ovog okvira 23. Primijetit ćete da dereference i 'adresa' operatera su obrnuto proporcionalni jedna drugoj. To mi omogućuje da učinite nešto poput * & * & n = 42. Dok to radi, nikada ne biste trebali učiniti nešto ovako u praksi. O čemu se zapravo radi ovdje? Prvi znak za struju dočepa adresu varijable n. Zatim, imamo dereference operatera, što znači da ćemo se na tu adresu u memoriji, tako da smo se vratili na n. Sada smo zgrabiti adresu n opet i odmah dereference, tako da smo se vratili na n i trgovine 42. Dakle, svaki par * & samo poništava. Tu je posebna pokazivač zove null pokazivač. Ovo je pokazivač da mi nikada ne bi dereference. Takav pokazivač je važno jer nam daje način da razlikujete između pokazivač koji bi trebali i ne bi trebao biti dereferenced. Ako pokušate dereference null pokazivač, obično vaš program će se srušiti s segmentacije krivnjom, što ste možda vidjeli prije. Dakle, recimo da imamo kod int * x = null; * x = 4. U ovom primjeru, to se može činiti očito da radimo nešto loše, ali sjetite se da nulta zaista mogla biti vrijednost vratio iz poziva na funkciji kao malloc, ako malloc ne može dodijeliti memoriju tražene od strane korisnika. Iz tog razloga, ako umjesto toga smo postavili vrijednost x iz poziva malloc, kao u int * x = malloc (sizeof (int)), onda mi uvijek treba eksplicitno provjerite vidjeti ako null vraćen. Ako (x == null); / / uhoh! povratak; još možemo nastaviti i reći * x = 4. Dakle, opet, zašto bi mi ikada koristiti pokazivače? Pogledajmo primjer programa gdje trebamo koristiti pokazivače - jednostavna zamjena funkcija. Recimo imam dva broja, int x = 4, a int y = 15; i želim napisati funkciju zove zamjena da mogu koristiti ovako: zamijenite (x, y). Nakon ove linije, vrijednosti unutar varijable x trebao biti 15, a vrijednost unutar varijable y bi trebao biti četiri. Vrijednosti unutrašnjost xiy su zamijenili. Bez pokazivače, možemo pokušati nešto poput praznina swapa (int, int b); int tmp = b, b =; = tmp. No, ne možete primijetiti problema s time? Sjetite se da je vrijednost pohranjena u varijabli je samo kopija vrijednosti x, a vrijednost u b kopira od y. Sve promjene koje su napravljene na A i B neće se odraziti na xiy. Dakle, dok se vrijednosti A i B pravilno zamijeniti, X i Y nisu uopće promijenio. Sada, neka je promijeniti swap funkciju, tako da su njegovi argumenti su pokazivači varijable treba swap, ovako: void zamjena (int *, int * b); int tmp = * b, * b = *, * = tmp. Zapamtite da zamijeni argumenti su sada upućuje, i tako moramo proći adresu xiy u pozivu za swap, ovako: zamijeniti (& x, & y). Ovo je sada ispravno swapovi su vrijednosti xiy. Ajmo nacrtati okvir-i-strelica dijagram vidjeti zašto se to radi. Mi smo započeli s našim dvije kutije u memoriji, X i Y. Unutar okvira za x je broj 4, a unutar okvira za y imamo 15. Sada, unutar poziva na swap funkciju, imamo još dvije kutije za argumente a i b; a ukazuje na okvir za X, a B ukazuje na kutiji za y. Novi okvir stvoren za varijablu tmp, i unutar njega možemo pohraniti rezultat dereferencing b, što znači 'slijediti strelicu iz kutije s oznakom b ". Dakle, mi pohraniti 15 unutrašnjost tmp. Zatim, možemo slijediti strelicu na b i pohraniti ovdje rezultat dereferencing, što je vrijednost 4. Konačno, možemo slijediti strelicu na i trgovine što je trenutno unutar tmp, koja je 15 godina. Primijetit ćete da su kutije s oznakom X i Y ispravno zamijenili vrijednosti. Nakon što smo saznali više o malloc i dinamičke memorije upravljanje, Vidjet ćemo da nemamo izbora nego koristiti pokazivače. Šetajući box-a sa strelicom shemi za bilo koji program može vam pomoći shvatiti što je program stvarno radi. Moje ime je Rob Bowden, a ovo je CS50. [CS50.TV] To je drugačije korištenje za zvjezdicom - bleah, mrzim tu riječ. Bilo gdje smo se samo reći n, sada možemo reći pointer_to_n - ne možete can't - * pointer_to_n.