*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