Föreläsning 6 pekare och pekare tillsammans med arrayer



Relevanta dokument
Föreläsning 10. Pekare (Pointers)

*Pekarvärden *Pekarvariabler & *

Agenda. Arrayer deklaration, åtkomst Makron Flerdimensionella arrayer Initiering Strängar Funktioner och arrayer. Övningar nu och då

Programmering, grundkurs, 8.0 hp, Elektro, KTH, hösten Programmering: att instruera en maskin att utföra en uppgift, kräver olika språk:

Programmering, grundkurs, 8.0 hp HI1024, HI1900 etc., Tentamen TEN1. Måndagen den 10 januari 2011,

Att använda pekare i. C-kod

Programmeringsteknik med C och Matlab

TDIU01 - Programmering i C++, grundkurs

Planering Programmering grundkurs HI1024 HT 2014

Övningsuppgifter till föreläsning 2 Variabler och uttryck

Programmering, grundkurs, 8.0 hp HI1024, omtentamen, TEN1. Tisdagen den 7 juni 2011,

HI1024, Programmering, grundkurs, 8hp KTH STH TENTAMEN. HI1024:TEN2 - Praktisk tentamen Tid: Fredagen den 21 oktober 2011,

Programmera i C Varför programmera i C när det finns språk som Simula och Pascal??

Planering Programmering grundkurs HI1024 HT TIDAA

Föreläsning 5: Introduktion av pekare

Dagens program. Programmeringsteknik och Matlab. Objektorienterad programmering. Vad är vitsen med att ha både metoder och data i objekten?

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Planering Programmering grundkurs HI1024 HT data

1 Funktioner och procedurell abstraktion

Minnestilldelning (allokering) och frigörande (avallokering) av minne

Grundläggande C-programmering del 2 Pekare och Arrayer. Ulf Assarsson

Föreläsning 6: Introduktion av listor

Grundläggande C-programmering del 2 Pekare och Arrayer. Ulf Assarsson

2.1 Variabler. 2.2 Regler för namngivning i C. Programmering, grundkurs, 8.0 hp, Elektro, KTH, hösten Föreläsning 2

HI1024 Programmering, grundkurs TEN

Att förstå hur man konstruerar modulära program Att kunna skapa nya funktioner Att förstå hur data skickas mellan funktioner

HI1024 Programmering, grundkurs TEN

TDDC76 - Programmering och Datastrukturer

Övning från förra gången: readword

Funktioner och programstruktur. Föreläsning 5

Beräkningsvetenskap föreläsning 2

Föreläsning 3.1: Datastrukturer, en översikt

HI1024 Programmering, grundkurs TEN

C++ Funktioner 1. int summa( int a, int b) //funktionshuvud { return a+b; //funktionskropp } Värmdö Gymnasium Programmering B ++ Datainstitutionen

Föreläsning 5-6 Innehåll. Exempel på program med objekt. Exempel: kvadratobjekt. Objekt. Skapa och använda objekt Skriva egna klasser

Föreläsning 2. Variabler, tilldelning och kodblock{} if-satsen Logiska operatorer Andra operatorer Att programmera

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Föreläsning 5-6 Innehåll

Programmering, grundkurs, 8.0 hp, Elektro, KTH, hösten 2010

HI1024 Programmering, grundkurs TEN

Parameteröverföring. Exempel. Exempel. Metodkropp

HI1024, Programmering, grundkurs, 8hp KTH STH TENTAMEN. HI1024:TEN1 - Teoretisk tentamen Tid: Torsdagen den 20 oktober 2011,

Boken?!?! Vad är ett program? Kompilerande-Interpreterande Programmeringsmiljö Hello World! Att programmera och ett enkelt program Variabler printf

Klassdeklaration. Metoddeklaration. Parameteröverföring

6.1 Kompilering och lite grundläggande information

C++ Lektion Tecken och teckenfält

Programmering C: Tentamen of 5 Prioritet och associativitet hos operatorerna i C De viktigaste operatorerna: Prioritet Kategori Operator

Övningsuppgifter kapitel 8

HI1024 Programmering, grundkurs TEN

Objektorienterad Programmering (TDDC77)

Tentamen i. för D1 m fl, även distanskursen. lördag 26 februari 2011

Funktioner och programstruktur. Föreläsning 5

I Skapa Hej.java och skriv programmet. I Kompilera med javac Hej.java. I Rätta fel och repetera tills du lyckas kompilera ditt program

Operatorer Tilldelning Kodblock { } if satsen Logiska uttryck Att programmera

Övningsuppgift. En array baklänges. Steg 1. Författare: Mats Loock Kurs: Inledande programmering med C# Kurskod:1DV402

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Checklista. Föreläsning 1-2 Innehåll. Programmering.

Uppgifter till praktiska tentan, del A. (7 / 27)

Datorteknik 2 (AVR 2)

Johan Karlsson Datavetenskap för teknisk kemi, 10p, moment 1 Datavetenskap Umeå Universitet. Tentamen

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Skriv i mån av plats dina lösningar direkt i tentamen. Skriv ditt kodnummer längst upp på varje blad.

1 Texthantering. 1.1 Typen char. Exempel, skriv ut alfabetet

Uttryck och villkor. Föreläsning 2

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

TDIU01 - Programmering i C++, grundkurs

Introduktion till programmering och Python Grundkurs i programmering med Python

struct egendefinierad typ struct LECTURE_TYPE { char teacher[99]; float lengthinminutes; char type; /* L = lecture, E = exercise */ };

Arrayer (vektorer) Murach s: kap Elektronikcentrum i Svängsta AB

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Muddy. Funktioner / metoder. Punktnotation. Evalueringsordning

4 Sammansatta datatyper

Alla filer som bearbetar PHP script ska avslutas med ändelsen.php, exempelvis ska en indexsida till en hemsida heta index.php

IS1200 Datorteknik. Övning CE_O4 Maskinnära programmering med C Förberedelser till hemlaboration 1

Föreläsning 3-4 Innehåll

Labora&on 2 Funk&oner, if och loop övningar/uppgi:er

Värmedistribution i plåt

Programmeringsteknik och Matlab. Dagens program. Viktiga datum. Repetitionsexempel. Repetition av if/else, for, while och Scanner

Användarhandledning Version 1.2

TUTORIAL: SAMLING & KONSOLL

Tentamen i. Programmering i språket C

Dynamiskt minne. Vad är dynamiskt minne Motivering Hur gör man i C Övningar

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Frekvenstabell över tärningskast med C#

Hej Då, Karel! Programmering. Vårt första Javaprogram. hh.se/db2004. Java. Grundtyper, variabler och arrayer

TDDC77 Objektorienterad Programmering

Alla datorprogram har en sak gemensam; alla processerar indata för att producera något slags resultat, utdata.

Länkade listor kan ingå som en del av språket, dock ej i C Länkade listor är ett alternativ till:

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

KTH STH TENTAMEN. HI1024:TEN2 - Praktisk tentamen Tid: 8-13, den 18 februari 2012

Föreläsning 8: Structar

Programmering, grundkurs, 8.0 hp HI1024, TEN1. Fredagen den 2 mars 2012

TDIU01 - Programmering i C++, grundkurs

Programmering, grundkurs, 8.0 hp HI1024, extra tentamen, TEN1, för TIDAA1. Fredagen den 11 mars 2011,

Om pekare och minneshantering i C, relaterat till operativsystem och särskilt konstruktionen fork() execvp().

Uppgift 1 (grundläggande konstruktioner)

C++ Slumptalsfunktioner + switch-satsen

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Exempelduggan. Luffarschack. Koda spel

Tentamen i Programmering grundkurs och Programmering C

Objektorienterad programmering i Java

Transkript:

Föreläsning 6 pekare och pekare tillsammans med arrayer Vi ska nu undersöka vad pekare egentligen är och hur de relaterar till arrayer. Det är ett centralt tema i C-programmering. Vi följer boken och går successivt igenom de viktiga avsnitten. Datorns minne och 11.1 Pointer variables, pekarvariabler Datorns minne är indelat i små delar, den minsta delen heter en bit och lagrar en etta eller en nolla. 8 bitar grupperas ihop i bytes och varje byte i datorn har ett ordningsnummer, detta kallas för en adress. En adress är ett då ett heltal som varierar mellan 0 (lägsta adressen) och datorns högsta adress som väldigt ofta är cirka 4 miljarder, då talar vi om en dator med 4 gigabyte i internminne. En adress är alltså ett heltal, men vi kan inte lagra adresser i vanliga heltalsvariabler, för att lagra en adress måste vi använda så kallade pekarvariabler, eller kortare, pekare. En pekarvariabel (eller pekare) kan alltså innehålla alltså ett heltal som är adressen till ett lagringsutrymme i datorn. Vi studerar ett exempelprogram: main() int a, b, c; a = 10; b = 20; c = 30; printf("variabelnamn\t\tvarde\t\tadress\n"); printf("\ta\t\t%d\t\t%u\n", a, &a); printf("\tb\t\t%d\t\t%u\n", b, &b); printf("\tc\t\t%d\t\t%u\n", c, &c); Dess körning visas nedan: Variabelnamn Varde Adress a 10 2356706844 b 20 2356706840 c 30 2356706836 Vi får tag i en variabels adress med hjälp av adressoperatorn &, så &a betyder adressen till a. Vi ser att adresserna till variablerna a, b och c slutar på 844, 840 respektive 836. Vi kan skapa en bild av hur detta är organiserat i minnet med ledning av siffrorna 10, 20 och 30 (de värden som variablerna innehåller) och variablernas adresser som vi benämner 836, 840 och 844. Så här kan vi föreställa oss det: Adress Värde 836 30 840 20 844 10 Variabelnamnen lagras inte i datorns minne i den körbara filen, de hör till källkoden, int maskinkoden. Datorn refererar alltid, under normal körning, till variablers adresser och aldrig deras namn. Vi har, i modellen av datorns minne, också sorteras minnescellerna i stigande adressordning. johnnyp@kth.se Sidan 1 av 9

Vi vill nu vill införa en pekare i ovanstående program, en pekare är en variabel som kan innehålla en adress som värde, vi vill alltså ha följande situation: Adress 836 30 840 20 844 10 Värde 848 840 Här har vi infört en ny variabel, med adress 848, och dess värde är 840 som är adressen till variabeln a. Detta kallas då en pekare eller pekarvariabel. Den deklareras så här: int *p;. 11.2 Adressoperatorn Vi ska snart återvända till pekarvariabeln, men först ska vi studera adressoperatorn. Man får tag i en variabels adress med hjälp av adressoperatorn som skrivs med ett och-tecken, alltså &. Det är precis den här vi använt väldigt ofta tillsammans med scanf() då vi matar in värden i körande program från tangentbordet. Men när vi vill införa en pekarvariabel (eller kortare pekare) måste vi deklarera den på ett speciellt sätt, om vi vill åstadkomma situationen som illustreras ovan kan vi skriva så här: int *p; (Som redan nämnt ovan.) p = &b; När p nu innehåller adressen till b säger vi att p pekar på b. Om vi inte skriver * i deklarationen av p så blir p en vanlig heltalsvariabel och då får vi inte göra tilldelningen p = &b. Vi måste alltså sätta dit * framför p och då kan vi lagra adressen till b i p. Observera att p själv då är en variabel som också har en adress, vi ska inte fundera så mycket över det nu dock. 11.2 Värdeoperatorn Adressoperatorn & tar alltså fram adressen hos en variabel. Men då vi har en pekare (som p ovan) så kan man också ta fram värdet på den minnesplats (variabel) som p pekar på. Vi gör det med hjälp av värdeoperatorn. Om vi skriver *p i situationen ovan kommer vi alltså åt b. Om vi utvidgar vår modell av minnet och även annoterar variabelnamn i marginalen (trots att de inte finns i datorns minne) kan detta se ut så här: Deklarationer och satser i programmet Visualiering av resultatet i datorns minne int *p, a, b, c; a=10; b=20; c=30; p=&b; I figuren har vi valt att symbolisera att p pekar på b genom att rita in en pil. Det ser vi också genom att innehållet i p är 840 som är just adressen till variabeln b. johnnyp@kth.se Sidan 2 av 9

Värdeoperatorn är också en stjärna, *, som används i koden som ska utföra någonting. Uttrycket *p är ett så kallat lvalue, förkortning för left-hand-side-value som alltså kan stå till vänster om en tilldelningsoperator. Om vi utför en operation, som till exempel tilldelning, på *p så påverkas istället variabeln b. Det vill säga *p = 30 tilldelar variabeln b värdet 30. Vi kan utföra andra operationer också, skriver vi *p = *p + 1 så ökar vi b med 1, om vi skriver *p = a så tilldelar vi b värdet i variabeln a (som är 10.) 11.3 Tilldelningar till pekare När vi utför operationer på *p, där p är en pekare, som ovan, har vi sett att det som påverkas är det som p pekar på, ovan var det variabeln b. Men vi kan också arbeta direkt med värdet på p, alltså den adress som p innehåller. Vi gjorde det ovan då vi skrev p=&b, det var själva den operation som etablerade just det faktum att p pekar på b. Om vi nu har två pekare till heltal som är deklarerade så här: int *p, *q; så har de alltså möjlighet att peka på två olika platser i datorns minne. Om vi även har deklarerat två heltalsvariabler, i och j, och har gjort tilldelningarna p = &i och q = &j så pekar alltså p på i och q pekar på j. Vi studerar ett par olika sorters tilldelningar. Följande tilldelningar: *p = 1 och *q = 2 tilldelar, som vi vet, i värder 1 och j värdet 2. Följande tilldelning: *p = *q tilldelar i det värde som finns i j. Men följande tilldlning: q = p gör inte saker med i och j. Denna tilldelning ställer om vad q pekar på, efter denna tilldelning pekar q inte längre på j utan q pekar på i, precis som p. Det innebär att alla operationer på *q också påverkar i precis på samma sätt som *p påverkar värdet på i. Variabeln j är bortkopplad i och med tilldelningen q = p. 11.4 Pekare som argument Vi återvänder till deklarationen ovan, Deklarationer och satser i programmet Visualiering av resultatet i datorns minne int *p, a, b, c; a=10; b=20; c=30; p=&b; Många gånger har vi anropat funktionen scanf() för att läsa in ett heltal, om vi skulle gjort det med variabeln b ovan så kunde vi skrivit så här: scanf( %d,&b). Nu är det dock så att variabeln p redan pekar på b, det vill säga p innehåller redan &b. Det betyder att vi också kan mata in ett värde i variabeln b genom anropet scanf( %d,p), det ger exakt samma resultat som scanf( %d,&b). Anropet till scanf() med p eller, likvärdigt, &b som parameter är ett johnnyp@kth.se Sidan 3 av 9

exempel på då vi anropar en funktion med en pekare som parameter. Vi skickar alltså inte in värdet på b i scanf(), vi skickar in adressen till b så att funktionen scanf() vet var värdet på b ska placeras. Det är också så vi tänker när vi skickar en adress till en funktion, vi vill ofta förändra värdet på den variabel som parametern (en pekare) pekar på. Ett klassiskt exempel på en funktion som tar pekare som argument är den som byter plats på två variablers värde, vi kallar den swap() och ett program som visar visas nedan jämsides en provkörning där vi matar in värdena 10 respektive 20 i funktionen. swap(int * a, int * b) int tmp; tmp = *b; *b = *a; *a = tmp; Mata in x: 10 Mata in y: 20 x=20 y=10. main() int x, y, *p=&y; printf("mata in x: "); scanf("%d", &x); printf("mata in y: "); scanf("%d", p); swap(&x,&y); printf("x=%d y=%d.\n", x, y); Vi roar oss här också med att anropa scanf() med en pekarvariabel som pekar på y, men det hade vi kunnat strunta i. Om man inte skickar en pekarvariabel då man måste det så har resultatet ofta totalt katastrofala följder. Den funktion som förväntar sig en parameter kommer definitivt att använda värdeoperatorn på den parameter som den får in, som swap() gör på a och b ovan. Om vi inte har adressoperatorerna på anropet till swap() ovan, och alltså skickar in värdena 10 och 20 som värden på a och b, ja då försöker funktionen utföra sina operationer på de minnespositioner som har adresserna 10 respektive 20. Dessa adresser leder sannolikt till ett utrymme som programmet inte har tillåtelse att arbeta i, operativsystemet fångar upp detta och ser programmet som en brottsling och programmet utsätts för en påtvingad avstängning, en krasch som vi brukar säga. Detta har ni troligen råkat ut för många gånger då ni glömt adressoperatorn vid anrop till scanf(). 11.5 Pekare som returvärden Läs själva, inte så fasligt viktigt. johnnyp@kth.se Sidan 4 av 9

12 Pekare och arrayer HI1024 Programmering, grundkurs, 8.0 hp, KTH STH, hösten 2012 Vi ska nu se på släktskapet mellan pekare och arrayer. De är starkt kopplade i C och det kan man ofta utnyttja för att skapa mycket kraftfull kod. 12.1 Aritmetik utförd på pekare Vi kan få en pekare p att peka på första elementet i en array, så här, int a[10], *p=&a[0];. Då vi gör tilldelningen *p=5 lägger vi alltså in talet 5 på a[0]. Det intressanta här är att vi kan utföra vissa aritmetiska operationer på p. Om vi ökar p med 1, genom p++ eller p = p + 1 så flyttar sig pekaren p så att den pekar på nästa element i arrayen, här a[1]. Det är normalt inte så man först kanske skulle tänka sig resultatet, om vi ökar en variabels värde med 1 så ska väl värdet öka med 1? Nästa element i arrayen har ju en adress som är 4 heltalssteg över det förra värdet? Ett program illustrerar: main() int a[10], *p=&a[0]; printf("%u.\n", (unsigned int)p); p++; printf("%u.\n", (unsigned int)p); Detta programs körning ser ut så här: 2924698528. 2924698532. Det andra värdet som skrivs ut är fyra större än det första, men vi har genom operationen p++ väl bara adderat 1 till p, eller? Nej, pekararitmetiken föreskriver att när vi gör p++ så flyttar vi fram p så många steg som är storleken på det vi pekar på, i det här fallet int som har storleken 4. Operationen p++ resulterar alltså i att värdet på p ökar med 4, inte 1. I C kan vi göra följande aritmetiska operationer på pekare: 1. Addera heltal till en pekare (som ovan.) 2. Subtrahera ett heltal från en pekare (samma som ovan, fast man går åt andra hållet). 3. Subtrahera en pekare från en annan. Om de pekar in i samma array så blir resultatet det antal steg i arrayen som de respektive elementen (som pekarna pekar på) ligger från varandra. Ni får experimentera er fram till en förståelse av detta, ni behöver inte använda er av pekararitmetik och sannning att säga så har jag aldrig gjort det. Det är fullt tillräckligt att arbeta med index till arrayer och göra aritmetiska operationer på index istället för pekare som pekar in i den array man arbetar med. Men vi ska ändå undersöka detta lite mer. johnnyp@kth.se Sidan 5 av 9

12.2 Pekare till arrayer HI1024 Programmering, grundkurs, 8.0 hp, KTH STH, hösten 2012 Pekararitmetik fungerar i särskilt väl i loopar, vi kan gå igenom en array med en pekare på följande sätt: int a[10], *p; for(p=&a[0];p<&a[10];p++) gör något med *p Det står bara gör något med *p och det är förstås bara en abstraktion, i en riktig loop så utför vi någonting med *p och påverkar såldes arrayen. En likvärdig formulering utan pekararitmetik (som jag alltid använder), som ni klarar er alldeles utmärkt med, skulle vara int a[10], i; for(i=0;i<10;i++) gör något med a[i] Det är någonting som är konstigt med for(p=&a[0];p<&a[10];p++). Vad kan det vara? OBS: När man kombinerar värdeoperatorn, alltså * på pekare, och inkrementeringsoperatorn, alltså ++ på pekare, så måste man vara noggrann med precendensen, alltså vilken operator som utförs först. Personligen avstår jag från pekararitmetik, man kan klara sig utan det. Men för er som är intresserade av pekararitmetik är det viktigt att ni speciellt läser avsnittet Combining the * and ++ Operators, på sidan 262. Alla behöver läsa detta avsnitt för att kunna förstå denna kod, förstå skillnaden mellan uttrycken *p++, (*p)++, ++p och ++*p. Men i er kod kan ni alltid välja att separera inkrementeringsoperatorn (++) och värdeoperatorn (*) för tydlighetens skull. Man kan också använda parenteser för att skapa extra tydlighet gällande vad som utförs först. Boken föreskriver ibland i övningarna att man ska använda pekararitmetik, men ni kan göra som ni vill där. Vi ser på ett par exempel. Värdet av *p++ är samma sak som *p, efter detta värde använts ökas p med 1. Istället för koden q = *p++; kan man istället skriva q = *p; //Alltså först göra det man vill med *p p++; //och därefter öka p med 1. Det är tydligare att skriva på det sätt som illustreras precis ovan för det betonar att vi ökar p:s värde, inte värdet på *p. 12.3 Ett arraynamn som pekare En mycket viktig och kraftfull egenskap då det gäller släktskapet mellan arrayer och pekare är att själva namnet på en array kan användas som pekare till arrayens första element. Det vill säga om vi har deklarationen int a[10]; så är namnet, alltså a, samma sak som &a[0]. Vi kan alltså skriva *a = 7 så läggs 7 in på a[0], och *(a+1) = 12; så lägger vi in 12 på plats a[1]. johnnyp@kth.se Sidan 6 av 9

Vi kan förenkla loopar som går igenom arrayer ytterligare, istället för att skriva for(p=&a[0];p<&a[10];p++) gör något med *p så kan vi skriva for(p=a;p<a+10;p++) gör något med *p Men jag föredrar personligen att faktiskt bara arbeta med index (här deklarerat ovan som int i), som sagt jag avstår från pekararitmetik, och bara skriva for(i=0;i<10;i++) gör något med a[i] även om det blir lite mer kod. Att skicka arrayer till funktioner, avsnitt 12.3 (array arguments revisited) och 12.4 Det absolut viktigaste med detta avsnitt, släktskap mellan arrayer och pekar är egenskapen att vi kan skicka en pekare till en array som parameter till en funktion genom att bara använda arraynamnet. Vi ska studera ett av kursens bästa exempel som bokens funktion find_largest() som ser ut så här: int find_largest (int a[], int n) int i, max; max = a[0]; for (i=1;i<n;i++) if(a[i]>max) max = a[i]; return max; main() int tal[] = 5, 3, 7, 6, 9, 1; printf("largest: %d.\n", find_largest(tal, 6)); Vi har även lagt in ett litet testprogram som inte finns i boken för att illustrera hur vi anropar find_largest(). En körning ser ut så här: Largest: 9. Alltså arrayens största element (9) skrivs ut. Vi ser här klart och tydligt hur arraynamnet, tal, används direkt i anropet, i funktionen tar vi emot en array av tal, int a[], men vi skulle lika gärna kunna haft parameterdeklarationen int *a, alltså int find_largest (int *a, int n). johnnyp@kth.se Sidan 7 av 9

Att skicka tvådimensionella arrayer som parametrar till funktioner Vi behöver inte undersöka släktskapet mellan pekare och flerdimensionella arrayer i fullständig detaljrikedom, men vi behöver veta hur man skickar tvådimensionella arrayer till funktioner. För att kunna diskutera detta behöver vi först förtydliga vad som händer vid ett funktionsanrop och hur parametrarna hanteras. Vi studerar ett par exempel och börjar med ett minimalt exempel: int f(int x) return x+1; main() int a=5, b; b=f(a); Vad händer när detta program kör? Översiktligt, vi skickar a = 5 till funktionen som tar emot värdet 5 i parametern x, och skickar tillbaka x+1 som alltså är 5+1 som alltså kommer tillbaka i variabeln b i huvudprogrammet. Variabeln b har alltså värdet 6 då programmet är klart. Det viktiga att poängtera här är att funktionen f får en kopia av värdet på a. Värdet på a var 5 vid anropet och denna 5:a kopieras in i värdet på parametern x. Anropet innebär alltså att x tilldelas värdet 5. Eftersom lagringsutrymmena för variabeln a och parametern x är skilda åt är värdet i a skyddat. Funktionen påverkar inte det i framtiden. Faktiskt sker exakt samma sak om en parameter är en array, vi tittar tillbaka på exemplet ovan, find_largest. Vi väljer då att betona att parametern a i funktionen lika gärna kan anses vara en pekare, så vi ser alltså den alternativa definitionen nedan: int find_largest (int *a, int n) int i, max; max = a[0]; for (i=1;i<n;i++) if(a[i]>max) max = a[i]; return max; main() int tal[] = 5, 3, 7, 6, 9, 1; printf("largest: %d.\n", find_largest(tal, 6)); Vid anropet så skickas pekaren tal till funktionen find_largest(). Låt oss anta att den har värdet 1000. Ett löjligt värde, men ändå, låt oss låtsas detta. Det som händer vid anropet är samma sak som i det minimala exemplet ovan, 1000, alltså adressen till arrayen tal, kopieras in i parametern a. När funktionen kör (efter den är anropad) har alltså parametern a värdet 1000. Det betyder att a, sedd som pekare, pekar på tal[0], och i loopen som följer refereras till a[i] där i går igenom 1 till och med 5 (styrt av den andra parametern n, som här har värdet 6.) När funktionen refererar till a[i] kan alltså funktionen undersöka innehållet i arrayen tal via a som är en pekare till arrayen tal. Obserevera att arrayens adress, tal, levereras till funktionen på precis samma sätt som det mycket simpla exemplet med f ovan. johnnyp@kth.se Sidan 8 av 9

Det är alltså bara adressen till första elementet som skickas då man skickar ett arraynamn som parameter till en funktion. Och det enda som skickas är alltså en startposition. Det innebär en komplikation då man ska skicka tvådimensionella arrayer. Vi ser på ett enkelt exempel där vi vill skicka en tvådimensionell array till en funktion. Antag att vi har följande kod. f(int a[][]) int r, c; a[0][0] = 0; a[1][2] = 0; for(r=0;r<2;r++) for(c=0;c<3;c++) printf("%d ", a[r][c]); printf("\n"); main() int tal[2][3] = 1, 2, 3, 4, 5, 6; f(tal); I huvudprogrammet bildar vi en tvådimensionell array som heter tal och så skickar vi den till funktionen f. I minnet representeras en tvådimensionell array enligt principen row-major, en 2x3-array, alltså med 2 rader och 3 kolumner, läggs då ut i minnet i hela rader, så innehållet i minnet blir någonting i stil med [1 2 3 4 5 6], alltså först första raden (1 2 3) följt av andra raden. (Vi skulle kunna tänka oss column major också och ha representationen [1 4 2 5 3 6], men det har vi inte.) Problemet här är att funktionen f, som inte alls vet något annat än startadressen för den tvådimensionella arrayen, inte vet hur många element som finns i varje rad, alltså antal kolumner, en klump data som har representationen [1 2 3 4 5 6] skulle lika gärna kunna varit en 2x3- array och inte en 3x2-array. Vi måste ange det i parameterdeklarationen för funktionen. Deklarationen ovan är alltså inte korrekt, om vi kompilerar denna kod får vi meddelandet error: array type has incomplete element type kompilatorn säger då att typen på arrayen (array type) är ofullständigt angiven, (incomplete). Vi gör deklarationen fullständig genom att ange hur många kolumner den tvådimensionella arrayen har genom följande nya funktionsdeklaration: f(int a[][3]) Nu fungerar programmet som det är tänkt, alltså programmet skickar in 2x3-arrayen i funktionen som nollställer första och sista elementet och skriver ut resultatet med en nästlad loop. Resultatet ser ut så här: 0 2 3 4 5 0 Sammanfattningsvis: Pekare och arrayer är starkt kopplade. Då det gäller parametrar till funktioner är de identiska, en array-parameter ÄR en pekare. Vi behöver inte fundera så mycket kring pekare till enstaka rader som boken gör. johnnyp@kth.se Sidan 9 av 9