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 numberThis will be allocated on the stack.
Variable-size array
int size;
cin >> size;
int arr[size]; // variable numberThis will be allocated on the stack too.
Dynamically allocate memory for the array
int size = 7;
int* arr = new int[size]; // dynamically allocate memoryThis 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++) {
arr2p[i] = new int;
}for (int i = 0; i < 4; i++) {
*arr2p[i] = i + 1;
}for (int i = 0; i < 4; i++) {
delete arr2p[i];
arr2p[i] = NULL;
}delete [] arr2p;
arr2p = NULL; // arr2p -> NULLCan we dynamically allocate an array of objects? Yes.
class Student {
public:
string name;
int ID;
Student() { ID = 0; name = ""; }
~Student() { cout << "Destructor" << endl; }
}
int main() {
// Default constructor called 3 times
Student* arr = new Student[3];
// Destructor called 3 times
// no destructor will be called without delete
delete [] arr;
arr = NULL;
return 0;
}Can I have an array of pointers to objects? Yes
int main() {
// no constructors called
Student** arr2p = new Student*[3];
......
for (int i = 0; i < 3; i++) {
arr2p[i] = new Student;
}
......
for (int i = 0; i < 3; i++) {
arr2p[i]->ID = i + 1;
}
......
for (int i = 0; i < 3; i++) {
delete arr2p[i];
}
......
delete [] arr2p;
arr2p = NULL;
}Read at home: Recap on Memory Management Issues
Losing access to a dynamically allocated space
int *p = new int;
*p = 100;
p = new int; // memory leakSolution: Have a delete before making p point to a new memory space.
int *p = new int;
*p = 100;
delete p;
p = new int;Access a freed memory space
int *p = new int;
*p = 100;
delete p;
*p = 3; // challenging to debugSolution: It is a good practice to set the pointer to NULL or nullptr after delete.
Dereference an undefined pointer
int *p;
int y;
y = *p; // p has garbage address
// defeferencing will access a garbage addressDouble free
int *p = new int;
delete p;
...
delete p; // double freeDelete a variable stored on the stack
int x = 4;
int *p;
p = &x;
delete p; // x is on stack, you can't delete itType mismatch assignment
int** <- int*,
int* <- int**,
int** <- int,
int* <- int
int *p, *q;
int **pp;
// pp: int**
// p: int*
pp = p; // type mismatch int** <- int*
// *p: p
pp = *p; // type mismatch int** <- int
p = pp; // type mismatch int* <- int**