TDP004 Minne och pekare Eric Elfving Institutionen för datavetenskap 1 / 23 Översikt • Internminne • Pekare • Dynamiska datastrukturer • (Enkellänkade) listor 2 / 23 Internminne - RAM • Datorns internminne (RAM, random access memory) består av en ordnad sekvens bitar • Vi kan normalt sett adressera (komma åt) en byte i taget (8 bitar) 3 / 23 Minne 4 / 23 Minne Vad händer i minnet? int x {3421}; int x: 3421 5 / 23 Variabler • En variabel har alltid: • Ett namn • En datatyp • Ett värde 5 / 23 Variabler • En variabel har alltid: • Ett namn • En datatyp • Ett värde • En adress 6 / 23 Pekare • En pekare lagrar en adress till en given position i minnet • Deklareras med en asterisk (*) int * ip; 7 / 23 Pekare • Man kan ta fram adressen till en variabel med adressoperatorn (&) int x {3421}; int * ip {&x}; int x: ip: 3421 8 / 23 Pekare • För att komma åt det värde en pekare pekar på används avrefereringsoperatorn (*) #include <iostream> using namespace std; int main() { int x {3421}; int *ip {&x}; cout << ip << endl; cout << *ip << endl; return 0; } 14 3421 • Vi får bara avreferera pekare som pekar på adresser som vårt program äger 9 / 23 Pekare • Pekare används oftast för att skapa dynamiskt minne • Vi allokerar nytt minne med new-operatorn • Vi kan endast nå det nya utrymmet med hjälp av pekaren int* ip; ip = new int; *ip = 5123; int * ip {new int{5123}}; 10 / 23 Pekare Minnesläcka • Om vi redan pekar på en minnesadress och ber om nytt utrymme tappar vi bort det vi pekade på. int* ip {new int{44}}; int ip: 44 11 / 23 Pekare Minnesläcka int* ip {new int{44}}; ip = new int{123}; • Om vi redan pekar på en minnesadress och ber om nytt utrymme tappar vi bort det vi pekade på. int ip: 44 int 123 12 / 23 Pekare Minnesläcka • Om vi redan pekar på en minnesadress och ber om nytt utrymme tappar vi bort det vi pekade på. int* ip {new int{44}}; ip = new int{123}; int • Detta kallas minnesläcka, ett av de vanligaste felen när vi jobbar med pekare • Vi äger fortfarande utrymmet, men har inget sätt att nå det ip: 44 int 123 13 / 23 Pekare • Antag att vi har följande deklaration: int *ip {new int{345}}; int ip: 345 13 / 23 Pekare • Antag att vi har följande deklaration: int *ip {new int{345}}; int ip: 345 • Vi kan återlämna minnet med delete-operatorn delete ip; int ip: 345 13 / 23 Pekare • Antag att vi har följande deklaration: int *ip {new int{345}}; int ip: 345 • Vi kan återlämna minnet med delete-operatorn delete ip; int ip: 345 • OBS, delete ändrar inte på pekarens värde! 14 / 23 Pekare • Värdet nullptr betyder ¨inget värde¨ för pekare 1 2 3 4 int * ip{}; ip = new int{}; delete ip; ip = nullptr; // ip sätts till nullptr // det nya heltalet får värdet 0 kodrad: 1 Minnet: ip: 2 3 int ip: 0 4 int ip: 0 ip: 15 / 23 Pekare void f(int *p) { delete p; p = new int{2}; } int main() { int *ptr {new int{12}}; f(ptr); cout << *ptr << endl; delete ptr; } Vad händer? 16 / 23 Pekare Precis som vanligt måste vi ta emot referenser om vi vill ändra på värden: void f(int *& p) { delete p; p = new int{2}; } int main() { int *ptr {new int{12}}; f(ptr); cout << *ptr << endl; delete ptr; } 17 / 23 Alias • Om man tycker det är jobbigt med alla asterisker kan man skapa ett nytt namn för en typ med aliasdefinition • Skrivs på formen using NAMN = TYPBESKRIVNING; using int_ptr = int *; void f(int_ptr & p); int main() { int_ptr ptr { new int{4} }; delete ptr; } 18 / 23 Pekare till klasstyp • För att komma åt medlemmar i klasser kan man använda sig av medlemsåtkomstoperatorn (->) struct Book { string title; string author; int pages; }; Book *bp { new Book }; bp->title = "C++ Primer"; 18 / 23 Pekare till klasstyp • För att komma åt medlemmar i klasser kan man använda sig av medlemsåtkomstoperatorn (->) struct Book { string title; string author; int pages; }; Book *bp { new Book }; bp->title = "C++ Primer"; • Man kan använda avreferering också, men då krävs parenteser cout << (*bp).title << endl; 19 / 23 Dynamiska datastrukturer • En dynamisk datastruktur kan ändra storlek under programkörningen • Vi har redan stött på två dynamiska datastruktur, string och vector som kan lagra flera värden av en viss typ. 20 / 23 Dynamiska datastrukturer • Tänk er att vi vill stoppa in ett värde sorterat i en vector. Då behöver vi: • Hitta rätt position 7 0 4 12 17 0 1 2 3 20 / 23 Dynamiska datastrukturer • Tänk er att vi vill stoppa in ett värde sorterat i en vector. Då behöver vi: • • Hitta rätt position Utöka storleken 7 0 4 12 17 ? 0 1 2 4 3 20 / 23 Dynamiska datastrukturer • Tänk er att vi vill stoppa in ett värde sorterat i en vector. Då behöver vi: • • • Hitta rätt position Utöka storleken Flytta alla värden som ligger efter hittad position 7 0 4 12 17 ? 0 1 2 4 3 20 / 23 Dynamiska datastrukturer • Tänk er att vi vill stoppa in ett värde sorterat i en vector. Då behöver vi: • • • Hitta rätt position Utöka storleken Flytta alla värden som ligger efter hittad position 7 0 4 12 17 17 0 1 2 3 4 20 / 23 Dynamiska datastrukturer • Tänk er att vi vill stoppa in ett värde sorterat i en vector. Då behöver vi: • • • • Hitta rätt position Utöka storleken Flytta alla värden som ligger efter hittad position Stoppa in värdet 7 0 4 12 12 17 0 1 2 3 4 20 / 23 Dynamiska datastrukturer • Tänk er att vi vill stoppa in ett värde sorterat i en vector. Då behöver vi: • • • • Hitta rätt position Utöka storleken Flytta alla värden som ligger efter hittad position Stoppa in värdet 7 0 4 7 12 17 0 1 2 3 4 21 / 23 Enkellänkade listor • En enkellänkad lista består av noder sammankopplade med pekare. • En nod är en post som innehåller två saker, ett värde av någon datatyp samt en pekare till nästa nod i listan. • Detta gör en pekare till en nod till en lista. • Tom lista (eller slutet av listan) markeras med pekarvärdet nullptr. 3 7 9 22 / 23 Enkellänkade listor 3 7 9 23 / 23 Enkellänkade listor • Deklaration av en listtyp: struct List_Node { int data; List_Node * next; }; • Alternativ lösning med alias: struct List_Node; using List = List_Node *; struct List_Node { int data; List next; }; Eric Elfving Institutionen för datavetenskap www.liu.se