[Powered by Google Translate] [Pointers] [Rob Bowden] [Harvardin yliopisto] [Tämä on CS50] [CS50.TV] Puhutaanpa osoittimia. Tähän asti olemme aina vain tarkoitettu asiat muistiin nimenomaisesti nimen. Me olemme sanoneet int n = 42, ja sitten kun haluamme käyttää muuttujan n, me vain kutsumme sitä nimellä annamme sen kirjallisesti jotain n * 2. Mutta se muuttuja on elää jossain muistissa. Kun haluat käyttää arvoa, joka on tällä hetkellä varastoitu sisällä n, tai päivittää arvo n pitelee, ohjelma tarvitsee tietää missä muistissa etsiä n.. Jos muistissa muuttuja elämää kutsutaan sen osoite. Se on kuin talon osoite. Löydän jonkun talon kunhan tiedän heidän kotiosoite, ja tietokoneohjelma voi löytää muuttuva niin kauan kuin se tietää sen muistin osoite. Mikä osoittimet tarjoavat on tapa suoraan käsitellä näitä muisti osoitteita. Paljon valtaa C tulee pysty manipuloimaan muistiin näin. Mutta suurella voimalla tulee suuri vastuu. Osoittimet voidaan käyttää vaarallisesti riitä, että paljon ohjelmointikieliä piilottaa osoittimet kokonaan. Joten, miksi C antaa meille vinkin jälkeen? Kuten tiedätte, argumentteja C toiminto aina kopioidaan parametrien funktio. Joten, jossa jotain swap joitakin muuttujia x ja y ei voi vaihtaa arvot x ja y kutsuvan toiminto, vaikka se voisi olla kätevä. Kuten näemme myöhemmin, uudelleenkirjoitus swap ottaa osoittimia paikkoja tarvitse vaihtaa paikkaa ansiosta se vaikuttaa sen soittajan muuttujia. Kävellään läpi suhteellisen yksinkertainen esimerkki siitä, mitä viitteitä voi tehdä. Sanotaan meillä int n = 4; int * pointer_to_n = & n. Vau! Vähän uusia syntaksin kattamiseksi. Ensimmäinen, nyt tulkita tämän & N. Muista, että kaikki muisti on joissakin osoite. Et-kutsutaan "osoite" toimija. Niin, & n viittaa osoitteeseen muistissa, jossa n on tallennettu. Nyt olemme säilytä osoite uusi muuttuja, pointer_to_n. Mikä on tyyppiä tämän uuden muuttujan? Tähdellä on osa muuttujan tyyppi, ja me luemme tyyppiä int *. Int * tarkoittaa, että pointer_to_n on muuttuja, joka tallentaa osoitteen kokonaisluku. Tiedämme, että & n on int *, koska n on kokonaisluku, ja olemme ottaen osoitteen n. Int * on esimerkki osoittimen tyyppi. Heti kun alkaa nähdä tähtien tyyppi, tiedät, että olet tekemisissä viitteitä. Aivan kuten voimme julistaa muuttuja int x ja char y, Voimme sanoa int * z ja char * w. Int * ja char * ovat vain uudenlaisia ​​voimme käyttää. Sijainti * voi mennä minnekään ennen muuttujan nimeä. Joten molemmat int * pointer_to_n - kanssa * vieressä int, koska meillä on täällä - ja int * pointer_to_n kanssa * vieressä pointer_to_n ovat voimassa. Mutta täällä, minä sijoita * vieressä Int. Sillä ei ole väliä, mihin haluat, vain olla johdonmukaisia. Katsotaanpa piirtää kaavio tätä. Ensin on muuttuja n, jonka me tehdä niin pieni laatikko muistia. Tässä esimerkissä sanotaan, että tämä laatikko sijaitsee osoitteessa 100. Sisältä tämä ruutu, olemme tallennetaan arvo 4. Nyt meillä on uusi muuttuja, pointer_to_n. Se on oma laatikko muistiin, jotka sanomme on osoitteessa 200. Sisältä tämä ruutu, olemme tallennetaan osoitteen N, jota ennen mainittua oli 100. Usein kaavioita, näet tämän esitetty kirjaimellisesti nuoli jättäen pointer_to_n ruudussa osoittaa ruutuun joka tallentaa n.. Nyt, mitä me oikeastaan ​​tehdä pointer_to_n? No, jos sanomme jotain * pointer_to_n = 8, tämä on erilainen käyttö tähti , joka on täysin erillään käytön tähti todetaan muuttuvan osoittimen tyyppiä. Tässä, tähti kutsutaan dereference operaattori. Meidän kaavio, mitä * pointer_to_n = 8 tarkoittaa, Siirry laatikko sisältää pointer_to_n, seuraa nuolta, ja sitten määrittää laatikko lopussa nuolen arvo 8. Tämä tarkoittaa, että sen jälkeen, kun tätä linjaa, jos yritämme käyttää n sillä on arvo 8. Sana "osoitinta" käytetään paljon eri yhteyksissä. Täällä yritämme olla johdonmukaisia. Osoitin tyyppi on jotain int *. Tässä video, osoitin käytetään vain tarkoittavan arvon osoittimen tyyppi, kuten pointer_to_n joka on tyyppiä int *. Anywhere käytimme vain sanoa n, voimme nyt vaan sanoa * pointer_to_n, ja kaikki toimii yhtä hyvin. Kävellään läpi toisen yksinkertaisen esimerkin. Sanotaan meillä int n = 14; int * osoitin = &n; n + +, ja (* osoitin) + +. Ensimmäinen rivi luo uuden laatikon muistiin merkitty n.. Tällä kertaa emme merkitä laatikko selkeä osoite, mutta se on edelleen yksi. Sisällä laatikko, olemme tallennetaan numero 14. Seuraava rivi luo toisen ruudun osoitin. Ja sisällä tämä ruutu, olemme tallennetaan osoitin ruudun n. Joten, nyt piirtää nuoli osoitin n. Nyt, n + + askelin arvo ruudun n, joten menemme 14-15. Lopuksi (* osoitin) + + menee ruudun osoitin, dereferences arvo ruutuun, mikä tarkoittaa seuraa nuolta, jossa se toteaa, ja lisäyksin arvo tallennetaan siellä, niin mennään 15-16. Ja siinä se. N nyt tallentaa numero 16 tultuaan kasvatetaan kahdesti - kerran suoraan käyttämällä muuttujan nimi n ja muiden kautta pointer_to_n. Nopea tietovisa. Mitä mielestänne tarkoittaa jos yritän sanoa jotain && n? No, katsotaanpa kirjoittaa tätä & (& N), joka tekee saman asian. (& N) palauttaa osoitteen muuttuja n muistiin. Mutta sitten sitten ulompi et-yrittää palauttaa osoitteen osoitteen. Se on kuin yrittäisi tehdä & 2. Se ei ole järkevää saada osoitteen vain joidenkin numero koska se ei ole tallennettu muistiin. Käyttämällä kahta et-rivissä on koskaan oikea ajatus. Mutta nyt, mitä se tarkoittaa, jos yritän sanoa int ** double_pointer = & osoitin? Nyt olen uuden ruudun double_pointer, ja sisällä että laatikko olen tallennetaan osoitteen osoitin, mikä tarkoittaa Piirrän nuoli double_pointer ruutuun osoitin ruutuun. Ilmoitus tyyppi double_pointer, int **. N oli kokonaisluku, osoitin osoite on tallennettu n, ja niin se on tyyppiä int *. Nyt, double_pointer tallentaa osoitteen osoitin, joten se on tyyppiä int **. Joten, mitä me ajattelemme tämä tarkoittaa - ** Double_pointer = 23? Huomaa, että olen nyt dereferencing kahdesti. Vain seurata box-ja-nuoli kaavio olemme jo perustettu. Ensin menemme ruudun double_pointer. Ensimmäisen * tarkoittaa seuraa nuolta kerran. Nyt olemme ruudun osoitin. Toinen tähti sanoo seurata nuolta uudelleen, ja nyt me olemme ruudun n ja asetamme arvoa tämä jos haluat 23. Huomaa, että dereference ja "osoite" toimijat ovat käänteisesti verrannollisia toisiinsa. Tämä antaa minulle mahdollisuuden tehdä jotain * & * & n = 42. Vaikka tämä toimii, sinun ei pitäisi koskaan tehdä jotain käytännössä. Mitä me oikeastaan ​​teemme täällä? Ensimmäinen et-tarttuu osoite muuttujan n. Sitten meillä on dereference operaattori, mikä tarkoittaa, että olemme menossa kyseiseen osoitteeseen muistissa, joten olemme takaisin n.. Nyt meillä napata osoite n uudestaan ​​ja heti dereference, joten olemme takaisin n ja myymälä 42. Joten, jokainen pari * & vain kumoaa. On erityinen osoitin nimeltään nollaosoittimen. Tämä on osoitin, että meidän pitäisi koskaan dereference. Tällainen osoitin on tärkeä, koska se antaa meille tapa erottaa osoittimen, että pitäisi ja ei pitäisi dereferenced. Jos yrität dereference nollaosoittimen, tyypillisesti ohjelma kaatuu kanssa segmentointi vika, jotka olet ehkä nähnyt ennen. Joten Sanotaan meillä koodi int * x = null; * x = 4. Tässä esimerkissä se saattaa tuntua itsestään selvältä, että teemme jotain pahaa, mutta muista, että null voisi todella olla arvo palasi puhelun toiminto kuten malloc, jos malloc ei pysty osoittamaan muisti käyttäjän pyytämä. Tästä syystä, jos vaan asetamme arvon X puhelun malloc, kuten int * x = malloc (sizeof (int)), niin meidän pitäisi aina erikseen tarkistaa onko null palautettiin. Jos (x == null); / / uhoh! tuotto, muuten voimme jatkaa ja sanoa * x = 4. Joten jälleen, miksi meidän pitäisi koskaan käyttää osoittimia? Katsotaanpa esimerkki ohjelmasta, jossa meidän on käytettävä osoittimia - yksinkertainen swap-toiminto. Sanotaan Minulla on kaksi kokonaislukua, int x = 4; int y = 15; ja haluan kirjoittaa toiminto nimeltään swap, että voin käyttää näin: swap (x, y). Tämän jälkeen linjan, arvojen sisällä muuttujan x pitäisi olla 15, ja arvo sisälle muuttujan y pitäisi olla 4. Arvot sisälle x-ja y on vaihdettu. Ilman osoittimia, voisimme kokeilla jotain void swap (int, int b); int tmp = b, b = a; = tmp. Mutta, sinä huomaat ongelma tässä? Muista, että arvo tallennetaan muuttujaan on vain kopio x: n arvo, ja arvo b on kopioitu y. Tehdyt muutokset a ja b eivät näy x ja y. Joten, kun taas arvot a ja b on oikein vaihdettu, x ja y eivät ole muuttuneet lainkaan. Nyt, vaihda swap toiminto niin, että sen väitteitä ovat osoittimia muuttujat pitäisi vaihtaa, näin: void swap (int *, int * b); int tmp = * b * b = *, * = tmp. Muista, että swap argumentit ovat nyt osoittimia, joten meidän kulkea osoitteen x ja y puhelu vaihtaa, näin: vaihtaa (& x, & y). Tämä nyt oikein swap arvot x ja y. Katsotaanpa piirtää box-and-arrow kaavio nähdä miksi tämä toimii. Me aloitamme kaksi laatikkoa muistiin, x ja y. Sisällä ruutuun x on numero 4, ja sisällä laatikko y meillä on 15. Nyt sisällä puhelun swap toiminto, meillä on kaksi laatikkoa varten argumentteja ja b; viittaa laatikko x ja b viittaa laatikko y. Uusi laatikko luodaan muuttujaa tmp, ja sen sisällä me tulos tallennetaan dereferencing b, joka tarkoittaa "seuraa nuoli ruudun b." Joten Tallennamme 15 sisällä tmp. Sitten, me seuraamme nuolta b ja säilytä tässä tulos dereferencing, joka on arvo 4. Lopuksi seuraa nuolta ja tallentaa mitä tällä hetkellä sisällä TMP, mikä on 15. Huomaa, että laatikot on merkitty x-ja y ovat oikein vaihdettu arvot. Kun opimme lisää malloc ja dynaaminen muistinhallinta, näemme, että meillä ei ole muuta vaihtoehtoa kuin käyttää osoittimia. Kävely läpi box-ja-nuoli kaavio mihinkään ohjelmaan voi auttaa sinua selvittää, mitä ohjelma oikeasti tekee. Nimeni on Rob Bowden, ja tämä on CS50. [CS50.TV] Tämä on erilainen käyttö tähti - bleah, Vihaan sitä sanaa. Anywhere käytimme vain sanoa n, voimme nyt sanoa pointer_to_n - no te en voi - * pointer_to_n.