2. Pekere og referanser.

Like dokumenter
Pekere og referanser.

1. Introduksjon. Pekere og referanser.

HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring - AITeL

HØGSKOLEN I SØR-TRØNDELAG Avdeling for informatikk og e-læring - AITeL

1. Grunnleggende C Introduksjon til kurset og til C++ Innhold

Del 1 En oversikt over C-programmering

Dagens tema. C-programmering. Nøkkelen til å forstå C-programmering ligger i å forstå hvordan minnet brukes.

Kapittel 1 En oversikt over C-språket

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

Kort om meg. INF1000 Uke 2. Oversikt. Repetisjon - Introduksjon

INF 1000 høsten 2011 Uke september

INF1000 undervisningen INF 1000 høsten 2011 Uke september

Programmeringsspråket C

HØGSKOLEN I SØR-TRØNDELAG

HØGSKOLEN I SØR-TRØNDELAG

Inn og ut i C/C++ 1. Inn og ut i C/C++

Programmering i C++ Løsningsforslag Eksamen høsten 2005

Del 3. Pekere RR 2016

Litt om Javas håndtering av tall MAT-INF 1100 høsten 2004

Oversikt. INF1000 Uke 2. Repetisjon - Program. Repetisjon - Introduksjon

Del 2 Tabeller, arrays, strenger

Repetisjon: operatorene ++ og -- Java 5. Nøtt. Oppgave 1 (fra forrige gang) 0 udefinert udefinert. Alternativ 1 Prefiks-operator

INF1000 : Forelesning 4

i=0 i=1 Repetisjon: nesting av løkker INF1000 : Forelesning 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker j=0 j=1 j=2 j=3 j=4

Del 4 Noen spesielle C-elementer

8. Operator overloading

HØYSKOLEN I OSLO, AVDELING FOR INGENIØRUTDANNING

K O N T I N U A S J O N S E K S A M E N

E K S A M E N. Grunnleggende datakunnskap og programmering 02HIND*, 02HINE*, 02HDMU*, 02HING*, 02HGEOMAA, 02HSIV5

2 Om statiske variable/konstanter og statiske metoder.

Kontinuasjonseksamensoppgave i IMT1082 Objekt-orientert programmering

1 ØVING I WINDOWS FRA CHRISTIAN ANDOLO

Kontinuasjonseksamensoppgave i IMT1082 Objekt-orientert programmering

Oppsummering Assemblerkode Hopp Multiplikasjon Kode og data Array Oppsummering

Dagens tema INF1070. Vektorer (array er) Tekster (string er) Adresser og pekere. Dynamisk allokering

TDT4102 Prosedyre og Objektorientert programmering Vår 2015

Høgskolen i Gjøvik. Avdeling for elektro- og allmennfag E K S A M E N. EKSAMENSDATO: 12. desember 1995 TID:

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

Programmeringsspråket C Del 2

Dagens tema. C-programmering. Nøkkelen til å forstå C-programmering ligger i å forstå hvordan minnet brukes.

Kontinuasjonseksamen

Python: Løkker. TDT4110 IT Grunnkurs Professor Guttorm Sindre

Grunnleggende C++ Introduksjon til kurset og til C++

Beskrivelse av programmeringsspråket Compila15 INF Kompilatorteknikk Våren 2015

Programmeringsspråket C Del 2

Programmeringsspråket C Del 2

Eksamensoppgave i IMT1082 Objekt-orientert programmering

Vektorer. Dagens tema. Deklarasjon. Bruk

UNIVERSITETET I OSLO

LC191D Videregående programmering Høgskolen i Sør-Trøndelag, Avdeling for informatikk og e-læring. Else Lervik, januar 2012.

Introduksjon til objektorientert programmering

Oversikt. Introduksjon Kildekode Kompilering Hello world Hello world med argumenter. 1 C programmering. 2 Funksjoner. 3 Datatyper. 4 Pekere og arrays

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

Mer om C programmering og cuncurrency

INF1000 (Uke 5) Mer om løkker, arrayer og metoder

Høgskolen i Gjøvik Institutt for informatikk og medieteknikk E K S A M E N. Grunnleggende programmering

I dag INF1000 (Uke 4) Mer om forgreninger, While-løkker. Tre måter å lese fra terminal. Tre måter å lese fra terminal.

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

TDT4102 Prosedyreog objektorientert programmering Vår 2016

HØGSKOLEN I SØR-TRØNDELAG

LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke September 2012 Siri Moe Jensen EKSEMPLER

INF1000 (Uke 4) Mer om forgreninger, While-løkker

Argumenter fra kommandolinjen

Programmeringsspråket C Del 3

I dag INF1000 (Uke 4) Mer om forgreninger, While-løkker. Tre måter å lese fra terminal. Repetisjon. Mer om forgrening While-løkker

En oppsummering (og litt som står igjen)

Høgskolen i Gjøvik Avdeling for informatikk og medieteknikk. Eksamen. Objekt-orientert programmering

Programmeringsspråket C

Debugging. Tore Berg Hansen, TISIP

Programmeringsspråket C Del 3

OPPGAVE 1 OBLIGATORISKE OPPGAVER (OBLIG 1) (1) Uten å selv implementere og kjøre koden under, hva skriver koden ut til konsollen?

Kontinuasjonseksamen

Litt mer om uttrykk: ++ og -- INF1000 : Forelesning 4. Oppgave. Blokker. 0 udefinert udefinert. Alternativ 2 Postfiks-operator

HØGSKOLEN I SØR-TRØNDELAG

KONTINUASJONSEKSAMEN

Dagens tema C, adresser og pekere

Ark 3 av 26. printf("i adresse %08x ligger b med verdien %d.\n", &b, b); printf("i adresse %08x ligger a med verdien %d.

Eksamen. Grunnleggende programmering. EKSAMENSDATO: 6.desember 2016 TID: 16:00 20:00. (kalkulator er ikke tillatt)

Eksamen. Objekt-orientert programmering KLASSE(R): 02HIND* 02HDMU* 02HINE* 02HING* 01HINGA 02HSIV5 02HGEOMAA

Programmeringsspråket C

lage og bruke funksjoner som tar argumenter lage og bruke funksjoner med returverdier forklare forskjellen mellom globale og lokale variabler

Grunnleggende datakunnskap og programmering. EKSAMENSDATO: 16. desember 1997

Kontinuasjonseksamen

HØGSKOLEN I SØR-TRØNDELAG

løsningsforslag-uke5.txt

2 Om statiske variable/konstanter og statiske metoder.

KONTINUASJONSEKSAMEN

OBJEKTER SOM EN PROGRAMMERINGS-TEKNIKK

Programmeringsspråket C Del 3

INF1000 oppgaver til uke 38 (17 sep 23 sep)

INF1000. Marit Nybakken 10. februar 2004

Obligatorisk oppgave 1 INF1020 h2005

Programmeringsspråket C Del 3

Beskrivelse av programmeringsspråket Simpila INF Kompilatorteknikk Våren 2012

EKSAMEN. Dato: 9. mai 2016 Eksamenstid: 09:00 13:00

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Transkript:

Avdeling for informatikk og e-læring, Høgskolen i Sør-Trøndelag 2. Pekere og referanser. Mildrid Ljosland og Else Lervik 12.08.2013 Lærestoffet er utviklet for faget IFUD1048 C++ for programmerere med grunnlag i lærestoff fra LV195D Objektorientert programmering i C++ 2. Pekere og referanser. Resymé: Leksjonen gir en innføring i pekere og referanser, samt argumentoverføring. Innhold 1.1. Å LAGE OG BRUKE EN PEKER... 2 1.2. TABELL SOM PEKER... 3 1.3. CONST-PEKERE... 3 1.4. ARITMETIKK PÅ, OG SAMMENLIKNING AV PEKERE... 4 1.4.1. Å addere et heltall til en peker... 4 1.4.2. Å subtrahere to pekere... 6 1.4.3. Sammenlikning... 6 1.5. PEKERE MÅ BEHANDLES MED FORSIKTIGHET!... 7 1.6. REFERANSER... 8 1.7. ARGUMENTOVERFØRING... 9 1.7.1. Verdioverføring... 9 1.7.2. Referanseoverføring... 11 Referanse til læreboka: P. Deitel & H. Deitel: C++11 for Programmers, ch. 8. Annen referanse: Kap. 16.1-16.4 i Else Lervik og Mildrid Ljosland: Programmering i C++, Stiftelsen TISIP og Gyldendal, 2003 inneholder omtrent det samme som leksjonen.

2. Pekere og referanser. side 2 av 12 1.1. Å lage og bruke en peker En peker er en variabel som kan inneholde adressen til en annen variabel. En stjerne * i variabeldefinisjonen markerer at vi snakker om en peker. Eksempel: int tallet; int *pekeren; pekeren = &tallet; *pekeren = 6; Merk Når &-tegnet står på høyre side av = i en variabeldefinisjon eller i en tilordningssetning, betyr det at vi skal finne adressen til det som kommer bak, og la denne adressen være verdien til det som står på venstre side (eksempel: int *pekeren = &tallet;). Variablene tallet og pekeren er vist på figur 1. 100 tallet 6 tallet 6 101 pekeren 100 pekeren A: Peker tegnet som datacelle med adresse B: Peker tegnet som datacelle med pil Figur 1: To måter å representere en peker int *pekeren forteller at variabelen pekeren er en peker til en int, slik at den kan inneholde adressen til en int-variabel. Ved å skrive pekeren = &tallet gir vi pekeren en verdi som forteller hvor tallet er lagret. Hvis tallet er lagret på adresse 100, vil pekeren få verdien 100. *pekeren = 6 betyr at den adressen som pekeren viser til (adresse 100, dvs. tallet), skal få verdien 6. * kalles dereferanseoperatoren, og leses gjerne det som variabelen peker til. I vårt eksempel: Det som pekeren peker til er en int, og den skal få verdien 6. & er adresseoperatoren og leses "adressen til". I vårt eksempel: pekeren får som verdi adressen til tallet. & og * er motsatte operatorer, de opphever hverandre. Uttrykket *&pekeren betyr det samme som &*pekeren og det samme som pekeren. Ved å bruke en peker, kan vi bruke en variabel uten å angi navnet på den. *pekeren = 6 forandrer verdien på variabelen tallet, men gjør ingenting med pekeren. Dette kalles indirekte adressering, og utnyttes i en del situasjoner.

2. Pekere og referanser. side 3 av 12 1.2. Tabell som peker I forrige leksjon nevnte vi så vidt at navnet på en tabell er en adresse. int tabell[10]; forteller kompilatoren at den skal sette av plass til ti heltall, og at tabell brukes som betegnelse for tabellen. Merk Når vi skriver bare tabell, tolkes det som adressen til første element i tabellen. Vi kan la en peker peke til et element i tabellen: int *heltallspeker = &tabell[4]; eller vi kan la pekeren peke til (begynnelsen av) tabellen: int *heltallspeker= tabell; som er det samme som int *heltallspeker= &tabell[0]; Når heltallspeker peker til begynnelsen av tabell, kan heltallspeker og tabell brukes om hverandre. Vi kan skrive tabell[2] = 5; heltallspeker[3] = 8; det samme som tabell[3] = 8 *heltallspeker = 0; det samme som heltallspeker [0] = 0 og som tabell[0] = 0 *tabell = tabell[2]; det samme som tabell[0] = tabell[2] Bruk den skrivemåten du syns er mest naturlig ut fra sammenhengen. 1.3. const-pekere Du er vant med å bruke const for å navngi en konstant, eksempel: const int maks = 100; Vi vil trenge å bruke const i forbindelsen med pekere. Det er med på å gjøre programmene våre sikrere. Eksempel: Du er kjent med strlen()-funksjonen for å finne lengden av en streng. Funksjonsprototypen ser slik ut: size_t strlen(const char *tekst); Når vi angir en peker på denne måten, betyr det at det som pekeren peker til, er konstant. Vi sier at det er en konstantpeker. Kompilatoren vil da passe på at vi ikke prøver å forandre det. Skriver vi tekst[0] = 'A' inni funksjonen, vil vi få kompileringsfeil. Merk at pekeren ikke er konstant, det er bare det den peker til, som er det. Dermed er det lov å skrive tekst = &tekst[1]; Vi kan ikke la en ikke-konstantpeker peke til det samme som en konstant-peker, for da kunne vi likevel ha forandret på det som konstantpekeren peker til. Det er altså ikke lov å skrive

2. Pekere og referanser. side 4 av 12 char *pekeren = tekst når tekst er definert som en konstantpeker, mens const char *pekeren = tekst går bra. Den motsatte veien går også bra. Det kan aldri skje noe galt om vi sier at en ikke-konstant skal betraktes som en konstant, dvs. vi kan la en konstantpeker peke til en variabel. Derfor kan vi godt la en variabel være aktuelt argument når det formelle er en konstantpeker. char entekst[81]; cin >> entekst; cout << "Lengden på teksten er " << strlen(entekst); For å angi at pekeren er en konstant, skriver vi int *const pekeren = &tall; Leses: Konstanten pekeren er en peker til int. Som andre konstanter, kan en pekerkonstant bare initieres, ikke tilordnes verdi. pekeren = &tall2; er ulovlig. Men det den peker til, kan godt forandres: *pekeren = 5; gjør at tall får verdien 5. Vi kan også lage en peker som både selv er en konstant, og det den peker til er en konstant: const int *const pekeren = &tall; Konstanten pekeren er en peker til en konstant heltalls-variabel. 1.4. Aritmetikk på, og sammenlikning av pekere Å utføre aritmetiske operasjoner på en adresse har bare begrenset interesse. Hva skulle f.eks. resultatet bety hvis vi multipliserer to adresser med hverandre? Følgende aritmetiske operasjoner er definert: Å addere et heltall til, eller subtrahere et heltall fra, en peker. Å subtrahere en peker fra en annen. Dessuten har vi følgende sammenlikningsoperasjoner: Å finne ut om to pekere er like eller ulike Å finne ut hvilken av to pekere som er størst eller minst 1.4.1. Å addere et heltall til en peker Når vi adderer 1 til en peker, vil den peke til neste variabel. Eksempel: double tabell[5]; double *pekeren; pekeren = tabell; pekeren peker til tabell[0] *pekeren = 0.0; tabell[0] får verdien 0.0 *(pekeren + 1) = *pekeren; tabell[1] får samme verdi som tabell[0] pekeren++; pekeren peker til tabell[1]

2. Pekere og referanser. side 5 av 12 Merk Når vi adderer et heltall til en peker flytter vi oss så mange variabler som tallet forteller. Addisjonen regnes i samme enhet som den datatypen pekeren peker til, uavhengig av hvor mange byte denne datatypen bruker. Uttrykket *(pekeren + N) betyr nøyaktig det samme som uttrykket pekeren[n] pekeren tabell[0] tabell[1] tabell[2] tabell[3] tabell[4] pekeren + 4 Figur 2: Pekeraddisjon Figur 2 viser at når pekeren peker til tabell[0], vil pekeren + 4 peke til variabelen fire plasser videre i minnet, dvs. tabell[4]. Følgende lille program viser hvordan pekeraddisjon virker: // // pekeraddisjon.cpp // #include <iostream > using namespace std; int main() { const int m = 5; int heltall[m]; double flyttall[m]; cout << "heltallsadresser:\n"; // Adressene skrives ut på heksadesimal form. for (int i = 0; i < m; i++) cout << (heltall + i) << endl; cout << "\nflyttallsadresser:\n"; for (i = 0; i < m; i++) cout << (flyttall + i) << endl; return 0; Kjøring av programmet: heltallsadresser: 1245032 Vi ser at adressene endrer seg med 4 for 1245036 hver gang i øker med 1. En variabel av 1245040 typen int legger beslag på 4 byte. 1245044 1245048

2. Pekere og referanser. side 6 av 12 flyttallsadresser: 1244992 En variabel av typen double legger beslag 1245000 på 8 byte. Dermed øker adressen med 8 hver 1245008 gang i øker med 1. 1245016 1245024 Pekeraddisjon kan utnyttes til å gå gjennom en hel tabell: const int lengde = 10; int tabell[lengde]; int *pekeren = tabell; for (int teller = 0; teller < lengde; teller++) { *pekeren = 0; pekeren++; Her starter vi med å la pekeren peke til element 0. Inni løkka får den variabelen som pekeren peker til, verdien 0, deretter blir pekeren sin verdi økt slik at den peker til neste element. Uttrykket *pekeren + 1 tolkes som (*pekeren) + 1 fordi + har lavere prioritet enn *. Ønsker vi verdien av det som pekeren + 1 peker til, må vi skrive *(pekeren + 1). En oversikt over prioritetene til operatorene finner du i vedlegg A i Deitel & Deitel (side 774-776). 1.4.2. Å subtrahere to pekere Vi kan finne antall elementer mellom to variabler, ved å ta differansen mellom adressene til dem. const char *tekst = "Et eksempel"; const char *start = tekst; while (*tekst!= '\0') tekst++; int lengde = tekst - start; cout << "Tekstlengden er lik " << lengde << endl; Eksemplet finner lengden til teksten Et eksempel. tekst og start er begge pekere. Differansen mellom dem forteller hvor langt det er mellom adressene de peker til. Som ved addisjon, regnes differansen i samme enhet som det pekerne peker til. Hvis tekst - start har verdien 2, er det to tegn mellom det som start peker til og det som tekst peker til. Utskriften fra eksemplet blir: Tekstlengden er lik 11 1.4.3. Sammenlikning To pekere av samme type kan sammenliknes med hensyn på likhet og ulikhet: if (peker1 == peker2)... tester om peker1 og peker2 inneholder samme adresse, dvs. peker til den samme variabelen. if (*peker1 == *peker2) tester om det de peker til, er likt. Alle pekere kan sammenliknes med 0. Vi kan også teste om en peker er større eller mindre enn en annen peker. Da vil vi finne ut hvordan det de peker til er plassert i forhold til hverandre i minnet. Vanligvis vil dette bare være aktuelt når vi ønsker å teste om et tabellelement er foran eller bak et annet.

2. Pekere og referanser. side 7 av 12 I eksemplet nedenfor definerer vi en tabell og to pekere. Den ene peker til begynnelsen av tabellen, og den andre til slutten. Deretter går vi i løkke og øker den første med 1 inntil den er lik den andre. // // sammenlikning.cpp // #include <iostream> #include <array> using namespace std; int main() { const int lengde = 5; int tabell[lengde] = {1, 2, 3, 4, 5; int *pekeren = tabell; // begynnelsen av tabellen int *slutt = &tabell[lengde]; // adressen rett etter tabellslutt while (pekeren < slutt) { // sammenlikning av pekere cout << "Verdien til slutt er " << slutt << ", til pekeren er " << pekeren << endl; cout << "Avstanden mellom pekeren og slutt er " << (slutt - pekeren) << endl; pekeren++; return 0; /* Utskrift: Verdien til slutt er 0x7fff54afea44, til pekeren er 0x7fff54afea30 Avstanden mellom pekeren og slutt er 5 Verdien til slutt er 0x7fff54afea44, til pekeren er 0x7fff54afea34 Avstanden mellom pekeren og slutt er 4 Verdien til slutt er 0x7fff54afea44, til pekeren er 0x7fff54afea38 Avstanden mellom pekeren og slutt er 3 Verdien til slutt er 0x7fff54afea44, til pekeren er 0x7fff54afea3c Avstanden mellom pekeren og slutt er 2 Verdien til slutt er 0x7fff54afea44, til pekeren er 0x7fff54afea40 Avstanden mellom pekeren og slutt er 1 */ 1.5. Pekere må behandles med forsiktighet! Når du tar i bruk pekere, vil du fort oppdage at det kan skje mye rart hvis du ikke passer nøye på. Advarsel Sørg alltid for at en peker peker til noe fornuftig før du bruker den! Som for enhver annen variabel, vil det alltid stå en eller annen verdi i pekeren når den opprettes. Siden denne verdien tolkes som en adresse, kan den lede hvor som helst i minnet. Det kan ha store konsekvenser å forandre på verdien i denne adressen. Du kan ha havnet i det området av minnet som styrer programutføringen. Da kan programmet gjøre merkelige ting "av seg selv", eller maskinen kan gå helt i stå. I heldigste fall kan du få en feilmelding. Det vil avhenge av hvilken kompilator du bruker.

2. Pekere og referanser. side 8 av 12 Eller du kan ha havnet i dataområdet for programmet ditt, slik at du forandrer verdi på en variabel uten å være klar over det. I en del tilfeller kan du være "heldig", slik at det ikke skjer noen synlig skade. Men da kan problemet dukke opp på et seinere stadium, f.eks. når du skal forandre litt på programmet, eller når du skal installere det hos oppdragsgiver... For å unngå å ødelegge noe på denne måten, er det en god regel å la alle pekere initieres til 0 (i C++ 11 kan vi bruke nullptr, som svarer til null i Java en peker som ikke peker til noe) hvis de ikke straks får en annen verdi. Adresse 0 brukes ikke til noe fornuftig, slik at du ikke kan ødelegge noe om du legger en verdi her. Men gjør du det, vil du kanskje få en feilmelding som lyder "Null pointer assignment" ved slutten av programutføringen. Og da er det helt sikkert en feil i programmet. 0 kan ikke betraktes som et vanlig tall i denne forbindelsen, andre tall enn 0 gir kompileringsfeil. Advarsel Ikke tro at du kan få en tabell ved å definere en peker! En tabell krever mange lagerplasser. Kompilatoren må ha beskjed om hvor mange lagerplasser som skal brukes. Hvis du derimot bare definerer en peker, setter kompilatoren bare av plass til pekeren. Eksempel: Skriver du char *linje; strcpy(linje, "Dette er farlig!!"); // strcpy() kopierer fra 2. til 1.argument, // se side 640-641 i boka vil det settes av plass til pekeren linje. Teksten vil bli lagret på den plassen linje peker til, som kan være hvor som helst siden linje ikke har fått noen verdi. Derfor kan den ødelegge andre ting, og selv bli ødelagt seinere i programmet. Skriver du derimot char *linje = "Dette går ganske bra!"; eller helst const char *linje = "Dette går helt bra!"; vet kompilatoren hvor mye plass den skal reservere, slik at tekststrengen blir lagret på et trygt sted, og linje satt til å peke til den. Men det blir reservert bare akkurat nok plass, så du kan få problemer hvis du forlenger teksten seinere i programmet, derfor er det lurt å la den være const. 1.6. Referanser En referanse er et ekstra navn på en allerede eksisterende variabel. int tallet; int &ref = tallet; ref = 6; tallet++;

2. Pekere og referanser. side 9 av 12 &ref betyr at ref er en referanse. int &ref kan leses "ref er en referanse til en int". Ved å skrive int &ref = tallet angir vi at ref skal være et annet navn på tallet. Da kan vi etterpå bruke både ref og tallet som betegnelse på den samme lagerplassen, slik at begge ender med å ha verdien 7 i eksemplet. tallet 7 ref Figur 3: En referanse Når &-tegnet står på venstre side av = i en erklæring, får vi en referanse (eksempel: int &ref = tallet;). En referanse kan ikke erklæres uten at vi samtidig forteller hvilken variabel den refererer til. 1.7. Argumentoverføring Vi har to typer argumentoverføring i C++: - Verdioverføring: Funksjonen jobber med en kopi av det aktuelle argumentet. Denne metoden brukes ved overføring av enkle variabler, dersom disse variablene er innargumenter. Metoden brukes også ved overføring av tabeller uansett om disse er inn-, inn- /ut- eller ut-argumenter. Da kalles det ofte adresseoverføring. (Dette svarer til argumentoverføring, slik du kjenner det i Java.) - Referanseoverføring: Funksjonen får en referanse til den aktuelle variabelen. Det vil si at funksjonen jobber med den samme variabelen som den kallende funksjonen, eventuelt under et annet navn. Denne metoden brukes for enkle variabler som er kombinerte inn-/utargumenter eller bare ut-argumenter. For objekter/strukturer er det vanlig å benytte denne metoden også for inn-argumenter, dette for å spare både plass og tid. Slike argumenter må da kvalifiseres med const, eksempel const string &navn, slik at en er sikret at funksjonen ikke endrer på verdien. Du vil se eksempler på dette i leksjon 3. (Referanseoverføring eksisterer ikke i C. Der bruker man adresseoverføring også for enkle variabler dersom de skal være ut-argumenter.) Vi skal se nærmere på argumentoverføring i lys av det nylig gjennomgåtte stoffet om pekere og referanser. 1.7.1. Verdioverføring Eksempel 1 const int makslengde = 10; int main() { int entabell[makslengde]; nullstill(makslengde, entabell);... void nullstill( int antall, // Inn int *tabell) { // Ut

2. Pekere og referanser. side 10 av 12 for (int teller = 0; teller < antall ; teller++) { tabell[teller] = 0; Inni funksjonen nullstill() er tabell erklært som en peker, men brukes som en tabell. I main() er entabell en adresse, og den brukes som aktuelt argument der funksjonen krever en peker. Bak kulissene skjer følgende ved kallet: int antall = makslengde; int *tabell = entabell; Det vil si at formelt argument settes lik aktuelt argument. I begge tilfellene har vi verdioverføring, det er verdiene til de aktuelle argumentene som sendes over. Vi ser at adresseoverføring er et spesialtilfelle av verdioverføring. De formelle argumentene vil fungere som lokale variabler inni funksjonen. Og her er tabell en peker. På grunn av at *(tabell + teller) er det samme som tabell[teller] kan vi inni funksjonen bruke []-notasjonen. Se figur 4. Siden tabell er erklært som en peker, vil det bare settes av plass til denne pekeren inni funksjonen. Tar vi sizeof(tabell) inni funksjonen, får vi beskjed om hvor mye plass en peker til int tar, i vår kompilator 4 byte. Hvis vi derimot tar sizeof(entabell) i main(), får vi vite hvor mye plass hele tabellen tar, i vårt eksempel 10 * 4 byte. Prøv det gjerne selv! Det at en tabell og en peker kan brukes om hverandre, kan vi utnytte til å "lure" funksjonen til å tro at tabellen starter et annet sted enn den i virkeligheten gjør. int *pekeren = &entabell[3]; nullstill(5, pekeren); gjør at entabell[3], entabell[4],...,entabell[7] blir nullstilt, mens de andre elementene blir stående urørt. Siden funksjonen får overført adressen til entabell[3], vil den tolke det som om tabellen starter der. tabell[0] vil derfor være entabell[3] og tabell[1] vil være entabell[4], osv. Vi trenger ikke å gå veien om pekeren. Vi kan også skrive nullstill(5, &entabell[3]); I hovedprogrammet: makslengde 10 entabell?????????? I nullstill(): antall 10 tabell int antall nullstill() = makslengde main() ; int *tabell nullstill() = entabell main() ; Figur 4: Verdioverføring

2. Pekere og referanser. side 11 av 12 Eksempel 2 Her er et eksempel på hvordan vi kan kopiere en tekststreng: void kopier(const char *fra, char *til) { while (*fra!= '\0') { *til = *fra; fra++; til++; *til = '\0'; Vi utnytter at adresseoverføring er verdioverføring. Adressene fra og til er verdioverført. Inni funksjonen kan de godt endres uten at det har noen innvirkning på de aktuelle argumentene. Bare når vi endrer det som pekerne peker til, får det varig virkning. Her ser vi også at vi bruker const foran argumentet fra. Det betyr at funksjonen ikke kan forandre på det denne pekeren peker til. Det er i samsvar med at dette argumentet er et innargument. Den som bruker funksjonen kan føle seg trygg på at tekststrengen fra ikke blir forandret. 1.7.2. Referanseoverføring Vi bruker referanser ved ut-argumenter i funksjoner: // // byttverdi.cpp // #include <iostream> using namespace std; void byttverdi(int &talla, int &tallb) { int hjelp= talla; talla = tallb; tallb = hjelp; int main() { int tallen; int tallto; cout << "Skriv to tall: "; cin >> tallen >> tallto; if (tallen > tallto) { byttverdi(tallen, tallto); cout << "I rekkefølge: " << tallen << " " << tallto; cout << endl; return 0; Det som skjer idet funksjonen kalles, er at de formelle argumentene initieres til de aktuelle argumentene. Det fungerer som om vi hadde skrevet setningene int &talla = tallen; int &tallb = tallto;

2. Pekere og referanser. side 12 av 12 talla og tallb blir referanser, og det de refererer til, er tallen og tallto. Så når talla får verdien tallb inne i funksjonen, så vil også tallen få denne verdien, siden det er den samme variabelen. (I motsetning til ved verdioverføring, da ville vi fått setningen int talla = tallen, slik at det ble to forskjellige variabler.)