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