*Pekarvärden *Pekarvariabler

*Pekarvärden
*Pekarvariabler
&
*
Motivering
• Pekare är ett fundamentalt koncept i C (och C++)
• Multipla returvärden från funktioner.
• Arrayer hanteras via pekare
• Dynamiskt minne (kommer i slutet av kursen)
kräver pekare.
Vad är en pekare?
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista i datorn
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
• Kan lagras i pekarvariabler
Vad är en pekare?
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista i datorn
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
Minnet
Adresser
• Kan lagras i pekarvariabler
0
...
...
42
43
44
45
46
47
”Vanliga” variabler
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
Minnet
Adresser
• Först lite om vanliga variabler:
0
• Deklaration av en variabel gör att
...
...
programmet när det kör reserverar x:
42
tillräckligt med minne för den och
43
sätter en etikett på denna ”låda”
44
45
int x;
46
47
”Vanliga” variabler
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
Minnet
Adresser
• Först lite om vanliga variabler:
0
• Deklaration av en variabel gör att
...
...
programmet när det kör reserverar x:
42
tillräckligt med minne för den och
43
sätter en etikett på denna ”låda”
7
44
• Tilldelning: värdet hamnar i lådan
45
int x;
x = 7;
46
47
”Vanliga” variabler
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
Minnet
Adresser
• Först lite om vanliga variabler:
0
• Deklaration av en variabel gör att
...
...
programmet när det kör reserverar x:
42
tillräckligt med minne för den och
43
sätter en etikett på denna ”låda”
77
44
• Tilldelning: värdet hamnar i lådan
45
• När variabeln används
46
int x;
kopieras värdet från lådan x = 7;
y = x + 4;
47
Åter till pekare
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
Minnet
Adresser
• Kan lagras i pekarvariabler
0
• För att skapa ett pekarvärde kan
...
...
man använda den unära
x:
42
operatorn &.
43
Om man t.ex. skriver ett uttryck
44
&x så får man adressen till x
45
(som i detta fall råkar vara 42)
int x;
46
47
Pekarvariabel
• Minnet kan lagra tal organiserat i 8-bitarsgrupper
(bytes)
• Alla bytes är organiserade i en lista
• Listan numreras från 0 och uppåt, kallas adresser
eller pekarvärden
Minnet
Adresser
• Kan lagras i pekarvariabler
0
• För att skapa ett pekarvärde kan
...
...
man använda den unära
x:
42
operatorn &.
43
Om man t.ex. skriver ett uttryck
44
&x så får man adressen till x
45
• Tecknet * används för att
46
px:
deklarera en pekarvariabel int x;
int *px;
47
48
Pekarvariabel
• Minnet kan lagra tal organiserat i 8bitarsgrupper (bytes)
• Alla bytes är organiserade i en lista
• Listan numreras från 0 och uppåt, kallas
adresser eller pekarvärden
Minnet
• Kan lagras i pekarvariabler
• För att skapa ett pekarvärde kan
...
man använda den unära
x:
operatorn &.
Om man t.ex. skriver ett uttryck
&x så får man adressen till x
• Tecknet * används för att
px:
deklarera en pekarvariabel int x;
int *px;
- som kan peka på saker:
px = &x;
Adresser
0
...
42
43
44
45
46
47
48
Utskrift
• Pekarvärden kan skrivas ut med printf med %p
(i allmänhet inte så värdefullt, men kan vara till
hjälp vid besvärlig felsökning). Ex:
#include <stdio.h>
x:
y:
int main(void) {
int x, y;
int *p; // p är en pekare till int
p:
p = &x; // p sätts att peka på x
printf(”x finns på adressen %p\n”, p);
return 0;
}
Pekarvariabel
• Pekarvariabler kan användas för att indirekt
komma åt värdet i de utpekade variablerna. Ex:
#include <stdio.h>
x:
y:
int main(void) {
int x, y;
int *p; // p är en pekare till int
p:
p = &x; // p sätts att peka på x
*p = 7; // Tilldelar det som p pekar på värdet 7
return 0;
}
7
Pekarvariabel
• Pekarvariabler kan användas för att indirekt
komma åt värdet i de utpekade variablerna. Ex:
7
#include <stdio.h>
x:
y:
int main(void) {
int x, y;
int *p; // p är en pekare till int
p:
p = &x; // p sätts att peka på x
*p = 7; // Tilldelar det som p pekar på värdet 7
return 0;
}
OBS! Samma tecken
men betyder helt
olika saker!!
Pekarvariabel
• Pekarvariabler kan användas för att indirekt
komma åt värdet i de utpekade variablerna. Ex:
#include <stdio.h>
x:
y:
int main(void) {
int x, y;
int *p; // p är en pekare till int
p:
p = &x; // p sätts att peka på x
*p = 7; // Tilldelar det som p pekar på värdet 7
y = *p; // Tilldelar y det som p pekar på
return 0;
}
7
7
I övrigt som vanligt
• Pekarvariabler Är i övrigt som vanliga variabler
– de kan tilldelas (pekarvärden)
– deras värden (pekarvärde) kan användas för att tilldela
andra pekarvaribler.
#include <stdio.h>
int main(void) {
int x, y, *a, *b;
a = &x; // a sätts att peka på x
b = &y; // b sätts att peka på y
...
a = b;// a sätts att peka på samma som b
return 0;
}
x:
y:
a:
b:
I övrigt som vanligt
• Pekarvariabler Är i övrigt som vanliga variabler
– de kan tilldelas (pekarvärden)
– deras värden (pekarvärde) kan användas för att tilldela
andra pekarvaribler.
#include <stdio.h>
int main(void) {
int x, y, *a, *b;
a = &x; // a sätts att peka på x
b = &y; // b sätts att peka på y
...
a = b;// a sätts att peka på samma som b
return 0;
}
x:
y:
a:
b:
&x
I övrigt som vanligt
• Pekarvariabler Är i övrigt som vanliga variabler
– de kan tilldelas (pekarvärden)
– deras värden (pekarvärde) kan användas för att tilldela
andra pekarvaribler.
#include <stdio.h>
int main(void) {
int x, y, *a, *b;
a = &x; // a sätts att peka på x
b = &y; // b sätts att peka på y
...
a = b;// a sätts att peka på samma som b
return 0;
}
x:
y:
a:
&x
b:
&y
I övrigt som vanligt
• Pekarvariabler Är i övrigt som vanliga variabler
– de kan tilldelas (pekarvärden)
– deras värden (pekarvärde) kan användas för att tilldela
andra pekarvaribler.
#include <stdio.h>
int main(void) {
int x, y, *a, *b;
a = &x; // a sätts att peka på x
b = &y; // b sätts att peka på y
...
a = b;// a sätts att peka på samma som b
return 0;
}
x:
y:
a:
&y
b:
&y
Övning
• Koden på föregående sida finns på hemsidan som
exempel 8.
• Lägg till kod (på lämpligt ställe) så att användaren kan
skriva in värden som tas emot i variablerna x och y
(genom att använda dessa).
• Skriv nu en tilldelningssats så att x får värdet av
summan av de två talen men använd bara
pekarvariablerna i tilldelningssatsen – inte x eller y.
• Skriv ut följande både före och efter den sista
pekartilldelningen:
– Värdena i x och y
– Värdena som pekas ut av a och b
– Värdena i a och b
• Ändra nu koden så att a och b används för inläsningen
(alltså i den scanf-sats som du har skrivit).
Pekarvariabel och typ
• En pekarvariabel är begränsad till att kunna peka på
en viss typ.
• Låter man den peka på en annan typ så blir det
oftast fel när man kör programmet (kompilatorn
varnar):
#include <stdio.h>
int main(void) {
char c;
int *y; y = &c; // Blir fel för y och &c har olika typ
...
return 0;
}
Tillämpning
• En använding av pekare är som nämnts att returnera
fler än ett värde från en funktion
• Ex: skriv en funktion gör en “frekvensanalys”:
– Ta reda på vilket heltal som förekommer flest gånger i en
array
– Håll reda på hur många gånger det förekom
– Både antalet gånger och vilket tal det är behöver komma
anroparen tillgodo
• Anta att alla talen är små t.ex. mindre än 1000.
Multipla returvärden - fel
int analyze_frequences(int arr[], int n) {
/* Return the number that is most frequent in the array and the number of
occurrences of that number */
return number, occurances;
}
int main(void) {
int arr[100]={1,2,3,4,2,2,3};
int number, occurances;
C har inte stöd
för multipla
returvärden
number, occurances = analyze_frequences(arr, 7);
printf(”%d %d\n”, number, occurances);
return 0;
}
Multipla data returneras - pekare
void analyze_frequences(int arr[], int n, int *number, int *occurances) {
/* Find the number that is most frequent in the array and the number of
occurrences of that number */
}
int main(void) {
int arr[100]={1,2,3,4,2,2,3};
int number, occurances;
analyze_frequences(arr, 7); // Error! re­write it correctly!
printf(”%d %d\n”, number, occurances);
return 0;
}
Övning
• Koden på förra sidan finns som exempel 9 på
hemsidan.
• Rätta till anropet till funktionen
analyze_frequences.
• Lägg till koden i funktionen analyze_frequences så
att den löser sin uppgift (som indikeras av
kommentaren).
Vanligt misstag
• Det är olämpligt att använda värdet av en ”vanlig
variabel” om den inte har getts något värde
int main(void) {
int x;
printf(”%d\n”, x); // Värdet är odefinierat
return 0;
}
• På samma sätt är det mycket olämplig att använda
ett odefinierat pekarvärde...
int main(void) {
int *q;
int x;
*q = 7; // Pekarvärdet är odefinierat!
q = &x;
return 0;
}
Summering
• Variabler kan vara av typen pekare
• En * i deklarationen bestämmer att de har typen
”pekare till någon typ”
char *v; // v är pekare till char
• En * intill en pekarvariabel i ett uttryck betyder ”det
som pekarvariabeln pekar på”
• Att tilldela en pekarvariabel utan * betyder att ändra
dess pekarvärde (till att peka på något annat)
• Man skapar ett pekarvärde med &. &m betyder en
perkare till m. Om m har typen t så har &m typen t*
Motivering
• Att kunna returnera fler än ett värde från en funktion
• Andra motiveringar blir klarare senare i kursen