Pekare
Från Unix.se, den fria unixresursen.
Här kommer en förklaring till en av de svåraste sakerna inom C- och C++-programmering. Egentligen är det här med pekare ganska enkelt, men det kan snabbt bli fel och felaktig använding av pekare är huvudorsaken till buggar i C- och C++-program. Ofta leder det till minnesläckage, att buffertar svämmar över, etc.
En pekare är en variabel vars värde är en minnesadress. Man säger att variabeln pekar på en annan variabel eller plats i minnet. Pekaren är alltså dels själv en variabel med en unik minnesadress, och dels pekar den på en annan unik minnesadress. Härav framgår att även om en pekare kan referera till strukturer av varierande storlek är pekarens egen storlek alltid densamma. Den specifika pekarstorleken beror på processorarkitekturen, och oftast är den då precis så stor att den kan peka på allt adresserbart minne. Exempelvis är pekare på 32-bitarsplattformar typiskt just 32 bitar (4 oktetter) stora.
Låt oss börja extremt enkelt genom att definiera upp en pekare i C:
char *ptr;
Variablen ptr är nu en så kallad char-pekare. Detta betyder att ptr
pekar på ett värde vars typ är char.
Om vi istället hade skrivit:
int *ptr;
så hade detta varit en int-pekare, vilket betyder att ptr
pekar på ett värde vars typ är integer (heltal).
Nu skall jag visa ett väldigt enkelt exempel på hur du använder pekare:
char c; char *ptr; ptr = &c; *ptr = 'A'; printf("ptr = %p, *ptr = %c, c = %c\n", ptr, *ptr, c);
Först deklarerar jag en char-variabel, c
och en char-pekare, ptr
.
Sedan lägger jag in adressen till char-variabeln c
i ptr
genom att skriva:
ptr = &c;
&-tecknet framför en variabel betyder i princip: "adressen till". Så i det här fallet blir raden ovan: Tilldela adressen för variabeln c
till ptr
.
När denna rad exekverats så kommer pekaren ptr
att peka på c
:s minnesadress.
Nästa rad:
*ptr = 'A';
betyder: Tilldela värdet som ptr
pekar på tecknet 'A'. Stjärnan framför innebär: ta vad pekaren pekar på. Detta kallas att avreferera pekaren. Som vi vet pekar ptr
på c
:s minnesadress och därmed blir ovanstående exakt samma sak som att skriva:
c = 'A';
Ungefär så här ser det alltså ut i minnet:
ptr -> [c] = 'A'
Alltså; ptr
pekar på c
:s minnesadress som i sin tur innehåller A.
Jag har illustrerat detta med printf-funktionen. Först skriver jag ut adressen till ptr
(%p), sedan skriver jag ut vad som finns på denna minnesadress och slutligen bara för att bevisa skriver jag även ut innehållet i c
.
Utskriften på min dator blir:
ptr = 0xbffff967, *ptr = A, c = A
Observera att du kan få en helt annorlunda minnesadress eftersom man aldrig vet var ledigt minne finns.
Nu skall jag visa hur du allokerar lite minne och fyller det med data. Till detta måste du använda pekare.
char *ptr; ptr = malloc(10);
Du har nu allokerat 10 byte:ar minne och ptr
pekar på den första positionen.
Ungefär så här ser det ut.
...XXXXXXXXXOOOOOOOOOOXXXXXX... ^- ptr
X representerar annat minne och O representerar det minne du har allokerat. Som du kan se så pekar vår pekare på första positionen i minnet.
OBS: minnet du allokerat är inte "nollställt" - det kan innehålla all möjlig gammal data.
Låt oss nu i undervisningssyfte fylla alla minnespositioner med ettor. Din pekare fungerar precis som en helt vanlig array i detta avseende.
for(i=0; i<10; i++) { ptr[i] = 1; }
Ett alternativt sätt att fylla ettor i det minne vi har allokerat skulle vara att flytta fram pekaren ett steg i taget och varje gång fylla på med en 1:a.
for(i=0; i<10; i++) { *ptr = 1; ptr++; }
Detta exempel visar mycket mycket tydligt på de olika sätten en pekare fungerar på.
*ptr
anger värdet i minnesadressen som pekaren pekar på.
ptr
anger själva minnesadressen som pekaren pekar på.
Kom ihåg att efter ovanstående kodsnutt så kommer ptr
att peka på slutet av minnet. Om du fortsätter att fylla på så kommer du att börja skriva i minne som du inte fått allokerat. Det är då bufferten svämmar över. Kärnan kommer då att säga: "Ajja bajja, detta är inte ditt minne!". Detta meddelar kärnan i form av en signal vid namn SEGFAULT (Segmentation fault), vilket är oerhört bra att veta. Om ditt program krashar på grund av SEGFAULT så brukar det till 99% bero på att du skriver utanför ditt allokerade minne.