[Powered by Google Translate] [Pekere] [Rob Bowden] [Harvard University] [Dette er CS50] [CS50.TV] La oss snakke om pekere. Frem til nå har vi alltid bare referert til ting i minnet eksplisitt etter navn. Vi har sagt int n = 42, og deretter når vi ønsker å bruke variabelen n, Vi kaller det bare ved navn vi gir den ved å skrive noe sånt n * 2. Men den variabelen må leve et sted i minnet. Når du ønsker å bruke den verdien som er lagret inne n, eller oppdatere verdien n holder, programmet trenger å vite hvor i minnet for å se etter n. Hvor i minnet en variabel liv kalles adresse. Det er som et hus adresse. Jeg kan finne noen hus så lenge jeg vet at deres hjemmeadresse, og et dataprogram kan finne en variabel så lenge det kjenner sin minneadresse. Hva pekere gir er en måte å direkte håndtere disse minneadresser. Mye av kraften i C kommer fra å være i stand til å manipulere minne som dette. Men med stor makt følger stort ansvar. Pekere kan brukes farlig nok at mye av programmeringsspråk skjule pekere helt. Så, hvorfor C gi oss tips da? Som du vet, argumenter til en C-funksjon kopieres alltid inn parametrene av funksjonen. Så ringer noe sånt swap på noen variabler x og y kan ikke forbyttes verdiene av x og y i den anropende funksjonen, selv om det kan være hendig. Som vi skal se senere, skrive swap å ta pekere til steder som trenger å byttes gjør det mulig å påvirke sin innringerens variabler. La oss gå gjennom en relativt grei eksempel på hva pekere kan gjøre. La oss si at vi har int n = 4, og int * pointer_to_n = & n. Whoa! En bit av ny syntaks å dekke. Først, la oss tolke dette & n. Husk at alt i minnet har noen adresse. Tegnet kalles "adressen" operatør. Så refererer & n til adressen i minnet hvor n er lagret. Nå er vi lagrer denne adressen i en ny variabel, pointer_to_n. Hva er den type av denne nye variabel? Stjernen er en del av den variable-typen, og vi vil lese den typen som int *. Int * betyr at pointer_to_n er en variabel som lagrer adressen til et heltall. Vi vet at & n er en int * siden n er et heltall, og vi tar adressen n. Int * er et eksempel på en peker attraksjon. Så snart du begynner å se stjerner i type, du vet at du arbeider med pekere. Akkurat som vi kan erklære en variabel som int x og røye y, Vi kan si int * z og røye * w. Int * og røye * er bare nye typer for oss å bruke. Plasseringen av * kan gå hvor som helst før variabelnavnet. Så, både int * pointer_to_n - med * ved siden int, som vi har her - og int * pointer_to_n med * ved siden pointer_to_n er gyldige. Men her skal jeg plassere * ved siden int. Det spiller ingen rolle hvilken du foretrekker, bare være konsekvent. La oss tegne et diagram for dette. Vi først har den variable n, som vi vil trekke som en liten boks med minne. For dette eksempelet, la oss si at denne boksen er plassert på adressen 100. Innsiden av denne boksen, vi lagrer verdien 4. Nå har vi en ny variabel, pointer_to_n. Det har sin egen boks i minnet, som vi vil si er på adressen 200. Innsiden av denne boksen, er vi lagrer adressen n, som vi før sa var 100. Ofte i diagrammer, vil du se dette vist som en bokstavelig pilen forlater pointer_to_n boksen peker til boksen som lagrer n. Nå, hva kan vi egentlig gjøre med pointer_to_n? Vel, hvis vi sier noe sånt * pointer_to_n = 8, er dette en annen bruk for stjernen som er fullstendig atskilt fra bruken av stjernen i å erklære en variabel av en peker type. Her blir stjernen kalles dereferanse operatør. I diagrammet vårt, hva * pointer_to_n = 8 betyr er, gå til boksen inneholder pointer_to_n, følger pilen, og deretter tilordne til boksen på slutten av pilen verdien 8. Dette betyr at etter denne linje, hvis vi prøver å bruke n det vil ha verdien 8. Ordet «viseren» er brukt i en rekke ulike sammenhenger. Her vil vi prøve å være konsekvent. En peker typen er noe som int *. I denne video, vil en peker bare brukes til å bety en verdi med en peker attraksjon, som pointer_to_n som har type int *. Hvor vi pleide å bare si n, kan vi nå i stedet si * pointer_to_n, og alt vil fungere like bra. La oss gå gjennom en annen enkelt eksempel. La oss si at vi har int n = 14; int * pekeren = &n; n + +, og (* pekeren) + +. Den første linjen skaper en ny boks i minnet merket n. Denne gangen vil vi ikke merke av i boksen med et uttalt adresse, men det har likevel ett. Innsiden av boksen, vi lagrer nummer 14. Den neste linjen oppretter en ny boks merket pekeren. Og innsiden av denne boksen, vi lagrer en peker til boksen merket n. Så, la oss trekke pilen fra pekeren til n. Nå, n + + øker verdien i boksen merket n, så vi går 14-15. Endelig (* pekeren) + + går til boksen merket pekeren, dereferences verdien i boksen, noe som betyr følge pilen til der den peker, og øker verdien lagret der, så vi går 15-16. Og det er det. N lagrer nå nummer 16 etter å ha blitt økes to ganger - gang direkte ved hjelp av de variable navn N, og den andre gjennom en pointer_to_n. Rask quiz. Hva tror du det betyr at hvis jeg prøver å si noe sånt && n? Vel, la oss skrive dette som & (& n) som oppnår det samme. The (& n) returnerer adressen til variabelen n i minnet. Men så da ytre ampersand forsøker å returnere adressen til adressen. Det er som å prøve å gjøre & 2. Det gjør ikke fornuftig å få adressen bare noen tall siden det ikke blir lagret i minnet. Ved å bruke to ampersand på rad er aldri den riktige ideen. Men nå, hva betyr det hvis jeg prøver å si int ** double_pointer = & pekeren? Nå er jeg oppretter en ny boks merket double_pointer, og innsiden av den boksen jeg lagre adressen pekeren, noe som betyr at jeg trekker en pil fra double_pointer boksen til pekeren boksen. Merke til type double_pointer, en int **. N var et heltall, pekeren lagrede adressen av n, og slik at den har type int *. Nå lagrer double_pointer adressen pekeren, så det har type int. ** Så, hva vi tror dette betyr - ** Double_pointer = 23? Legg merke til at jeg nå dereferencing to ganger. Bare følg boks-og-pil diagram vi har allerede satt opp. Først går vi til boksen merket double_pointer. Den første * betyr følge pilen en gang. Nå er vi på boksen merket pekeren. Den andre stjerne sier følge pilen igjen, og nå er vi på boksen merket n, og vi setter verdien av denne boksen til 23. Legg merke til at dereferanse og 'adresse' operatører er inverser av hverandre. Dette tillater meg å gjøre noe sånt * & * & n = 42. Selv om dette fungerer, bør du aldri gjøre noe som dette i praksis. Hva er vi egentlig gjør her? Den første ampersand griper inn adressen til variabelen n. Da har vi en dereferanse operatør, noe som betyr at vi skal til den adressen i minnet, så vi er tilbake på n. Nå, ta vi adressen n igjen og umiddelbart dereferanse, så vi er tilbake på n og lagre 42. Så, hvert par av * & kansellerer bare ut. Det er en spesiell pekeren kalt nullpeker. Dette er en peker som vi bør aldri dereferanse. Slikt pekeren er viktig fordi det gir oss en måte å skille mellom en peker som bør og ikke bør derefereres. Hvis du prøver å dereference en nullpeker, typisk programmet vil krasje med en segmentering feil, som du kanskje har sett før. Så, la oss si at vi koden int * x = null; * x = 4. I dette eksempelet kan det synes opplagt at vi gjør noe dårlig, men husk at null kan virkelig være en verdi returnert fra en samtale til en funksjon som malloc, er hvis malloc ikke tildele minne forespurt av brukeren. Av denne grunn, hvis vi i stedet sette verdien av x fra en samtale til malloc, som i int * x = malloc (sizeof (int)), så vi bør alltid eksplisitt sjekke for å se om null ble returnert. If (x == null) / / uhoh! retur, annet vi kan fortsette på og si * x = 4. Så, igjen, hvorfor skal vi noen gang bruke pekere? La oss se på et eksempel på et program der vi trenger å bruke pekere - en enkel swap-funksjon. La oss si jeg har to heltall, int x = 4, og int y = 15; og jeg ønsker å skrive en funksjon som heter swap som jeg kan bruke slik: swap (x, y). Etter denne linjen, må verdiene inne av den variable x være 15, og verdien inne variabel y bør være 4. Verdiene innsiden av x og y er byttet. Uten pekere, kan vi prøve noe sånt void swap (int a, int b); int tmp = b, b = a; a = tmp. Men, legger du merke til problemet med dette? Husk at verdien som er lagret i variabelen a er bare en kopi av verdien for x, og verdien i b er kopiert fra y. Eventuelle endringer a og b vil ikke bli reflektert i x-og y. Så, mens verdiene av a og b er korrekt byttet, x og y er ikke endret i det hele tatt. Nå, la oss endre swap-funksjonen slik at argumentene er pekere til de variablene det bør bytte, slik: void swap (int * a, int * b); int tmp = * b; * b = * a; * a = tmp. Husk at bytteavtaler argumenter er nå pekere, og så må vi passere adressen x og y i samtalen for å bytte, slik: swap (& x, og y). Dette nå riktig bytter verdiene av x og y. La oss tegne en boks-og-pil diagrammet for å se hvorfor dette fungerer. Vi starter med våre to bokser i minnet, x og y. Innsiden av boksen for x er nummer 4, og inne i boksen for y har vi 15. Nå, på innsiden av samtalen til swap-funksjonen, har vi to flere bokser for argumentene a og b; en peker til boksen for x, og b peker på boksen for y. En ny boks er opprettet for variable tmp, og på innsiden av det lagrer vi resultatet av dereferencing b, som betyr "følg pilen fra boksen b. Så lagrer vi 15 innsiden av tmp. Deretter følger vi pilen på b og lagre her resultatet av dereferencing a, som er verdien 4. Til slutt følger vi pil på et og lagre det som er på innsiden av tmp, som er 15. Legg merke til at boksene merket x og y har fullstendig byttet verdier. Når vi lærer mer om malloc og dynamisk minnehåndtering, Vi vil se at vi ikke har noe annet valg enn å bruke pekere. Vandre gjennom boks-og-pil diagram for hvilket som helst program kan hjelpe deg å finne ut hva programmet egentlig gjør. Mitt navn er Rob Bowden, og dette er CS50. [CS50.TV] Dette er en annen bruk for stjernen - bleah, jeg hater det ordet. Hvor vi pleide å bare si n, kan vi nå si pointer_to_n - nei du L ° vernes - * pointer_to_n.