0% found this document useful (0 votes)
4 views43 pages

03 Mem Linkedlist 1254

The document covers key concepts in C++ related to memory management, pointers, and linked structures. It includes announcements for assignments and emphasizes the importance of not sharing solutions publicly. Additionally, it explains memory areas, function parameters, dynamic memory allocation, and the structure of linked lists.

Uploaded by

fatimasaqib744
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views43 pages

03 Mem Linkedlist 1254

The document covers key concepts in C++ related to memory management, pointers, and linked structures. It includes announcements for assignments and emphasizes the importance of not sharing solutions publicly. Additionally, it explains memory areas, function parameters, dynamic memory allocation, and the structure of linked lists.

Uploaded by

fatimasaqib744
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 43

C++ Memory & Linked Structures

Memory
Pointers
Linked lists

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 1
Announcements

• IMPORTANT!
▪ Please do not post full or partial solutions (correct or otherwise) to graded activities (labs, HW, PA, exams) in
public Piazza posts
▪ If you must share code (but we encourage first careful inspection of your own logic, expected output vs
actual output), you can make a private Piazza post to instructors

Use Google document for lecture Q&A


• Lab_intro due Tuesday May 20, 22:00
• Lab_debug due Thursday May 22, 22:00

• HW1 due Tuesday May 20, 22:00 Coding practice activity released
Will be unavailable during exams
• PA1 released, due Saturday May 24, 22:00

• No class on Monday May 19 (Victoria Day holiday)

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 2
C++ and memory

• Think of computer's memory (RAM) as a long street


with numbered mailboxes 0
▪ each mailbox has its own number (e.g. 2A60)
▪ contains a value of a particular type (e.g. 21.03) 2A4C
▪ variables in the stack can be assigned names (e.g. double 2A50
geoffs_bank_balance) 2A54
2A58
double geoffs_bank_balance = 21.03; 2A5C
• 4 areas of memory 2A60 21.03
▪ code: compiled machine code instructions 2A64
2A68
▪ stack: small area for local variables/function parameters,…
2A6C
• automatically managed by system
▪ heap: (relatively) vast area for on-demand memory needs
• explicity managed by program code (you!)
▪ NULL: mailbox number zero

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 3
Calling functions in C++
Parameters

int a = 5; int sum(int x, int y) {


int b = 7; return x + y;
int result = sum(a, b); }

Formal parameters
Actual parameters

• Actual parameter
▪ Value(s) or variable(s) specified by the function caller
• Formal parameter
▪ Variables found in the signature/header of the function itself

• Formal parameters must match with actual parameters in order,


number, and data type

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 4
Function parameters

• Unless written otherwise, (most) parameters in C++ are passed by value ("call-by-value")
▪ the value of the actual parameter is copied to the formal parameter when the function is called

• The actual parameters and formal parameters are different variables in memory, even if they are
named the same

• If you change the value of the formal parameter, this does not affect the value of the actual
parameter back in the caller's memory

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 5
Function parameters and the call stack

• Example
// ... double circleArea(double radius){
int r = 3; double pi = 3.1415;
double area = circleArea(r); double sq_r = square(radius);
// ... return sq_r * pi;
}
double square(double x){
return x * x;
}

main memory

3 3.0 3.1415 3.0


r pi x
radius

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 6
Function parameters and the call stack

• Example
// ... double circleArea(double radius){
int r = 3; double pi = 3.1415;
double area = circleArea(r); double sq_r = square(radius);
// ... return sq_r * pi;
}
double square(double x){
return x * x;
}

main memory

3 3.0 3.1415 9.0


r pi sq_r
radius

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 7
Function parameters and the call stack

• Example
// ... double circleArea(double radius){
int r = 3; double pi = 3.1415;
double area = circleArea(r); double sq_r = square(radius);
// ... return sq_r * pi;
}
double square(double x){
return x * x;
}

main memory

3 28.274
r area

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 8
Call-by-value problems

int a = 5; void swap(int x, int y) {


int b = 7; int temp = x;
swap(a, b); x = y;
cout << "a: " << a << endl; y = temp;
cout << "b: " << b << endl; }

• Do the values really get swapped in the calling function?


▪ What does the call stack look like?

• This can be fixed using call-by-reference


▪ add a '&' symbol after the parameter's data type in the signature
▪ see sorting functions from our earlier slides about sorting algorithms

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 9
Dynamic memory
aka heap memory
• Variables declared in a function only exist within the scope of that function (or code block
enclosed by { } )
• The data structures we will learn about in this course require objects and variables to persist
beyond a function's lifetime
▪ cannot be allocated to call stack, need to put somewhere else
▪ heap memory / dynamic memory

• We still need local variables that refer or point to the dynamically allocated memory
▪ In C++ such variables are pointers

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 10
Addresses and pointers

• Every storage location in memory (RAM) has an address associated with it


▪ The address is the location in memory where a given variable or identifier stores its data
• Can think of address in memory like a mailbox number
▪ Use the address to find where the mailbox is
▪ Look inside the mailbox to access the contents/value

• A pointer is a special type of variable


▪ That stores an address rather than a value
▪ The address is used to find a value elsewhere in memory

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 11
Declaring pointers

• Pointer variables are declared as follows:


datatype* identifier
▪ e.g. int* ptr; or int * ptr; or int *ptr;
• Note that the type of a pointer is not the same as the type it points to
▪ e.g. ptr is a pointer to an int, but is itself not an int

• Warning! The declaration


int* var1, var2;
▪ declares var1 as a pointer, but var2 as an integer!
• To declare both as pointers, either declare individually, or:
int *var1, *var2;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 12
Address operator and dereferencing

• Pointers can be assigned the address of an existing variable


▪ Using the address operator, &
• The value which a pointer points to can be accessed by
dereferencing the pointer
▪ Using the * operator

p x
… 4096 … 23
0 1 212 220-1
int x = 23;

int* p = &x;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 13
Address operator and dereferencing

• Pointers can be assigned the address of an existing variable


▪ Using the address operator, &
• The value which a pointer points to can be accessed by
dereferencing the pointer
▪ Using the * operator

p x
… 4096 … 47
23
0 1 212 220-1
int x = 23;

int* p = &x;

x = 47;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 14
Address operator and dereferencing

• Pointers can be assigned the address of an existing variable


▪ Using the address operator, &
• The value which a pointer points to can be accessed by
dereferencing the pointer
▪ Using the * operator

p x
… 4096 … 47
38
0 1 212 220-1
int x = 23;

int* p = &x;

x = 47;

*p = 38;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 15
Pointers as parameters

• The formal parameter is a pointer variable, passed by value


void f1(int arg) int x = 45;
{
arg = 22; f1(x);
cout << "f1 arg: " cout << "x after f1: "
<< arg << "\n"; << x << "\n";
}
f2(&x);
void f2(int* arg) cout << "x after f2:
{ << x << "\n";
*arg = 410;
cout << "f2 *arg: "
<< *arg << "\n";
}

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 16
Pointer to a pointer
...to a pointer to a pointer...

int main() {
int x = 5;
int* p = &x;
*p = 6;
int** q = &p;
int*** r = &q;

cout << "*p: " << *p << endl;


cout << "*q: " << *q << endl;
cout << "**q: " << *(*q) << endl;
}

• "You can keep adding levels of pointers until your brain explodes or
the compiler melts – whichever happens soonest"
▪ stackoverflow user JeremyP

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 17
Type compatibility for pointer assignments

• “address of” operator – &


▪ &__ adds one “*” to the type of __
Variable Type
• Dereference operator – *
x int
▪ *__ removes one “*” from the type of __
&x int*
int x = 23;
p int*
int* p = &x; *p int
&p int**
*p = 38;
q int**
int** q = &p; y double
&y double*
double y = 2.25;
r double*
double* r = &y;
Different data types occupy different amounts of memory.
The pointer type tells the compiler how many bytes must be retrieved when dereferencing the pointer.
2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 18
Pointers and dynamic memory
Beware of memory leaks!
• The new keyword allocates space in dynamic memory and returns
the first address of the allocated space
• delete releases the memory at the address referenced by its pointer
variable
▪ delete[] is used to release memory allocated to array variables

int a = 5;
int* b = new int;
int* c = &a; allocates an array of size a
*c = 4; in dynamic memory (heap)
int** d = &b;
int* e = new int[a];
**d = 3;
int* f = new int[*b];
delete b;
delete e; // causes a memory leak
delete[] f;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 19
Dangling pointers

• When we are done with an allocated object, we free it so that the


system can reclaim (and later reuse) the memory
void fun() {
int* i = new int;
*i = 5;
delete i;
The space is marked as
free, but the value remains
until it is overwritten
cout << *i << endl;
}

• If the pointer continues to refer to the deallocated memory, it


will behave unpredictably when dereferenced (and the memory
is reallocated) – a dangling pointer
– Leads to bugs that can be subtle and brutally difficult to find
– So, set the pointer to NULL after freeing i = NULL;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 20
Memory leaks

• If you lose access to allocated space (e.g. by reassigning a pointer),


that space can no longer be referenced, or freed
▪ And remains marked as allocated for the lifetime of the program

int* arr;
int sz = 4;
arr = new int[sz];
arr[2] = 5;
arr = new int[sz];
arr[2] = 7;

stack heap
Lost access to
5 this array!
4
arr sz
7

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 21
Linked lists

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 22
Here's something new
and it doesn't have to be scary!

template <class LIT>


struct Node {
LIT data;
Node * next;
Node(LIT ndata, Node * nx=NULL):data(ndata),next(nx) {}
};
• template
▪ allow our containers to store any data type (at time of declaration)
• struct
▪ is like a class definition where all members are public by default
• Node definition uses itself
▪ not quite! next's type is Node*
• Inline constructor

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 23
Linked list nodes

• A linked list is a dynamic data structure that consists of nodes linked


together
• A node is a data structure that contains
▪ data
▪ the location of the next node

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 24
Node pointers

• A node contains the address of the next node in the list


▪ In C++ this is recorded as a pointer to a node
• Nodes are created in dynamic memory
▪ And their memory locations are not in sequence
• The data attribute of a node varies depending on what the node is intended to store

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 25
Linked lists

• A linked list is a chain of nodes where each node stores the address of the next node

Start

7 2 6 8

The slash indicates a


null pointer

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 26
Linked list implementation
Node class

template <class LIT>


struct Node {
LIT data;
Node * next;
Node(LIT ndata, Node * nx=NULL):data(ndata),next(nx) {}
};
next points to another
node, hence its type Node*

• attributes / members of a particular node can be accessed using the


'.' (dot) operator
▪ or the '->' (arrow) operator as a shorthand for pointer types
• equivalent to dereferencing and using dot operator

Node<int>* nd = new Node; nd->next = new Node;


(*nd).data = 5; nd->next->data = 12;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 27
Building a linked list

Assume we have written a parameterized


Node<int>* a = new Node<int>(7, null);
constructor for the Node class

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 28
Building a linked list

Node<int>* a = new Node<int>(7, null);


a->next = new Node<int>(3, null);

7 3

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 29
Traversing a linked list

Node<int>* a = new Node<int>(7, null);


a->next = new Node<int>(3, null);
Node<int>* p = a;
p = p->next; // go to next node
p = p->next;

7 3

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 30
Take a break!

© 1991, 2021 Square Enix Holdings Co., Ltd.

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 31
Linked list insertion

• Insertion in a singly-linked list requires only updating the next node


reference of the preceding position

15 16 19 22 28 …

p 17

b
Important!
Node<int>* b = new Node<int>(17, p->next); Be aware that sequential nodes are
not guaranteed to be found in
p->next = b;
sequential memory locations!

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 32
Linked list removal

• Likewise, we can remove a node by updating the pointer of the


preceding node
▪ but remember to delete the removed node!

15 16 19 22 28 …

p
b

p->next = b->next;
delete b;

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 33
Linked lists, by features
We will come back to this slide later
• Linkage • Termination • Access/entry

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 34
Some linked list variations

template <class LIT> template <class LIT>


struct Node { class LinkedList {
LIT data; private:
Node* next; Node* head;
Node* tail;
Node(LIT ndata, Node * nx=NULL): int length;
data(ndata),next(nx) {}
}; public:
LinkedList();
...
};

• Suppose we have a basic singly-linked list with a head pointer as


defined above
▪ operations at the back of the list have (relatively) poor complexity, requiring a
traversal
▪ but we can give ourselves a tail pointer for very little overhead, maintained
during operations at the back of the list

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 35
Singly-linked list with tail pointer
Insertion at back of list

head 1 2 3 4 6 7

tail

newnode

• We can now perform insertion at the back of list in 𝑂 1 time!


▪ What about insertion in the middle of the list?
▪ What about removal from the back of the list?

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 36
Doubly-linked list

• Node definition contains an additional pointer


▪ links to previous node in the list, allows traversal or access towards the front of
the list
template <class LIT>
struct Node {
LIT data; head
Node* prev; 5 2 9 6
Node* next;

// constructors, etc.
};

• Provides access to the previous and next nodes from a single


pointer (e.g. for insertion/removal)
– but, requires more pointer management in programming

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 37
Doubly-linked list insertion

• After some specified node


Node<int>* curr, * temp;
... // use a loop to move curr into place
temp = new Node<int>();
temp->data = 7;
temp->prev = curr;
temp->next = curr->next;
curr->next->prev = temp;
curr->next = temp;

head
6 12 4 23

curr

temp 7

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 38
Doubly-linked list removal

• At some specified node


Node<int>* curr;
... // move curr to the node to be removed
curr->next->prev = curr->prev;
curr->prev->next = curr->next;
delete curr;
curr = NULL;

head
6 12 7 4 23

curr

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 39
Linked list variations
Termination variants – Circular, sentinels
• Circular singly-linked list • Sentinel nodes
▪ “dummy” nodes at ends of lists which do not

contain any data
▪ eliminate special cases for list modifications
• e.g. insert/remove first/last node, all cases
implemented the same way

• Circular doubly-linked list S … S

2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 40
Linked lists are recursive!

• Iteration is convenient for many list operations (e.g. ordinary traversal, insertion, removal, etc.)
▪ but can be costly for other operations
• Consider printing the contents of a singly-linked list in reverse

head 12 25 3 44 18

template <class LIT> Running time? (our first recurrence)


void PrintReverse(Node<LIT>* curr) {

}
2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 41
Something slightly different

head 12 25 3 44 60 18

template <class LIT>


void PrintReverseEvenPositions(Node<LIT>* curr) {
// no items in list

// one item in list Running time?

// >1 item in list

2025S } Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 42
Something challenging!

head 12 25 3 44 18

head 18 44 3 25 12

return a pointer to the front of the reversed list


template <class LIT>
Node<LIT>* Reverse(Node<LIT>* curr) {
if (curr != NULL && ) {
Node* rev_end = ;
Node* rev_rest = ;
Running time?

}
return ;
}
2025S Will Evans / Steve Wolfman / Cinda Heeren / Jordon Johnson / Seva Lynov / Geoffrey Tien 43

You might also like