Lecture 13 - Oct 5, 2023
Summary
In this lecture, we discuss dynamic memory allocation of arrays (of objects and of pointers to objects).
Last lecture
Destructors.
Today
Dynamic memory allocation of arrays of objects and pointers to objects.
Double pointers
Double pointers are variables that store an address to a pointer.
Dynamic memory allocation of arrays
int a[4] = {1,2,3,4}
a
is an alias/nickname that has address to the first element in the array.
a <-> &a[0]
*a <-> a[0
*(a+1) <-> a[1]
There are different ways to have an array that stores data.
Fixed-size array
int arr[4]; // fixed number
This will be allocated on the stack.
Variable-size array
int size;
>> size;
cin int arr[size]; // variable number
This will be allocated on the stack too.
Dynamically allocate memory for the array
int size = 7;
int* arr = new int[size]; // dynamically allocate memory
This array will be allocated on the heap.
Advice: The programmer can “control” the lifetime of the array in the memory by freeing the memory anytime with delete
.
Can we dynamically allocate an array of pointers to integers? Yes.
int** arr2p = new int*[4];
for (int i = 0; i < 4; i++) {
[i] = new int;
arr2p}
for (int i = 0; i < 4; i++) {
*arr2p[i] = i + 1;
}
for (int i = 0; i < 4; i++) {
delete arr2p[i];
[i] = NULL;
arr2p}
delete [] arr2p;
= NULL; // arr2p -> NULL arr2p
Can we dynamically allocate an array of objects? Yes.
class Student {
public:
;
string nameint ID;
() { ID = 0; name = ""; }
Student~Student() { cout << "Destructor" << endl; }
}
int main() {
// Default constructor called 3 times
* arr = new Student[3];
Student
// Destructor called 3 times
// no destructor will be called without delete
delete [] arr;
= NULL;
arr
return 0;
}
Can I have an array of pointers to objects? Yes
int main() {
// no constructors called
** arr2p = new Student*[3];
Student
...
...
for (int i = 0; i < 3; i++) {
[i] = new Student;
arr2p}
...
...
for (int i = 0; i < 3; i++) {
[i]->ID = i + 1;
arr2p}
...
...
for (int i = 0; i < 3; i++) {
delete arr2p[i];
}
...
...
delete [] arr2p;
= NULL;
arr2p }
Read at home: Recap on Memory Management Issues
Losing access to a dynamically allocated space
int *p = new int;
*p = 100;
= new int; // memory leak p
Solution: Have a delete
before making p
point to a new memory space.
int *p = new int;
*p = 100;
delete p;
= new int; p
Access a freed memory space
int *p = new int;
*p = 100;
delete p;
*p = 3; // challenging to debug
Solution: It is a good practice to set the pointer to NULL
or nullptr
after delete
.
Dereference an undefined pointer
int *p;
int y;
= *p; // p has garbage address
y // defeferencing will access a garbage address
Double free
int *p = new int;
delete p;
...
delete p; // double free
Delete a variable stored on the stack
int x = 4;
int *p;
= &x;
p delete p; // x is on stack, you can't delete it
Type mismatch assignment
int** <- int*,
int* <- int**,
int** <- int,
int* <- int
int *p, *q;
int **pp;
// pp: int**
// p: int*
= p; // type mismatch int** <- int*
pp
// *p: p
= *p; // type mismatch int** <- int
pp
= pp; // type mismatch int* <- int** p