Presentation is loading. Please wait.

Presentation is loading. Please wait.

Memory Management CS101 2012.1. Chakrabarti Variable storage thus far  Never used global variables  All variables allocated inside functions, passed.

Similar presentations


Presentation on theme: "Memory Management CS101 2012.1. Chakrabarti Variable storage thus far  Never used global variables  All variables allocated inside functions, passed."— Presentation transcript:

1 Memory Management CS101 2012.1

2 Chakrabarti Variable storage thus far  Never used global variables  All variables allocated inside functions, passed by value or reference to other functions  In case of non-collection variables, the storage was always taken from the stack  In case of collection variables, storage was taken from the stack and the heap, but we did not need to understand how, or interfere

3 Chakrabarti Want a variable to outlive its scope  Same customer can have a checking account and a fixed deposit  Should not make copies of customer record  Supposing address or phone changes Customer makeCustomer(…) { … } Vs. Customer *makeCustomer(…) { … }  For simplicity let’s start with int variables

4 Chakrabarti new and delete int *pi = new int; *pi = 5; cout << pi << ' ' << *pi + 1 << endl; delete pi; pi points to an integer Allocates four bytes fom heap The value is always accessed as *pi Returns four allocated bytes to system: do this exactly once! The value is always accessed as *pi

5 Chakrabarti Pointer syntax TypeName *pointerVariableName;  TypeName is int, float, double etc. or the name of a class like vector etc.  * is the “pointer access” or “pointer dereference” operator  To read or write the storage holding the value of type TypeName, use *pointerVariableName in either the lhs or rhs  To read or write the pointer itself use pointerVariableName without a star

6 Chakrabarti Allocating arrays in the heap int nn = 5; int *pi = new int[nn]; for (int ix=0; ix < nn; ++ix) { cout << pi[ix] << endl; cout << *(pi+ix) << endl; } delete [] pi; Type remains same Allocates in heap space for nn ints Returns space back to heap (which remembers size but won’t tell you) Looks like array access Contents of cell ix integers after address pi

7 Chakrabarti The null pointer  Address 0 is not a legal address to read/write  Programs reliably fail if they attempt to do so  Therefore, int *pa = 0; is a safe initializer until memory is allocated (or after it is freed)  But 0 is of type int, while pa is of type int * (pointer to int )  Therefore a type cast is required int *pa = (int*) 0;  Can do this will any type in place of int

8 Chakrabarti Null pointer for classes class Customer { public: static Customer * const null; }; Customer * const Customer::null = (Customer*) 0;  Can now use Customer::null anywhere  Cleaner than (Customer*) 0 everywhere

9 Chakrabarti Our own vector class: specification class Vector { public: Vector(); Vector(const Vector& other); ~Vector(); void insert(int p, float v); float remove(int p); float get(int p) const; int size() const; } Promises that these methods will not modify the Vector in any way Default constructor: empty vector Copy constructor Destructor

10 Chakrabarti Vector implementation  Three private fields  Native array pa of floats allocated on heap  int cap recording the number of floats that can fit in the array (capacity)  int siz recording the number of floats currently in the array (from position 0 onward)  Invariant: siz  cap  Run out of space: allocate larger array, copy  siz << cap : allocate smaller array, copy

11 Chakrabarti insert void insert(int p, float v) { if (siz + 1 <= cap) { // enough space } else { float *nPa = new float[siz+1]; int wx = 0, rx = 0; while (rx < p) { nPa[wx++] = pa[rx++]; } nPa[wx++] = v; while (rx < siz) { nPa[wx++] = pa[rx++]; } if (cap > 0) { delete [] pa; } cap = siz = siz + 1; pa = nPa; } pa p nPa v

12 Chakrabarti Our own queue class: specification class Queue { // of ints, say public: bool isEmpty() const; int removeFirst(); void pushLast(int val); void print() const; private: QueueElement *first, *last; };

13 Chakrabarti Queue implementation struct QueueElement { int value; QueueElement *next; QueueElement(int v) : value(v), next(null) { } }

14 Chakrabarti Printing a queue QueueElement *pqe = first; while (pqe != null) { cout value << endl; pqe = pqe->next; } valuenextvaluenext pqe

15 Chakrabarti Constructor and destructor Queue::Queue() { first=last=null; } Queue::~Queue() { while (first != null) { QueueElement *pQe = first; first = first->next; delete pQe; } first next pQe

16 Chakrabarti pushLast void Queue::pushLast(int val) { QueueElement *pQe = new QueueElement(val); if (first == null) { first = pQe; } if (last != null){ last->next=pQe; } last = pQe; } last val pQe

17 Chakrabarti removeFirst int Queue::removeFirst() { int ans = first->value; QueueElement *pQe = first; first = first->next; delete pQe; return ans; }

18 Chakrabarti Binary search tree  A binary tree is either empty  Or it has a root node  With two children left and right  Each of which is a binary tree  Suppose each node contains an int key  Assume no duplicate keys for starters  The tree is a search tree if All keys in left are smaller than the root All keys in right are larger than the root

19 Chakrabarti Search tree from main() TreeNode *root = null; for (;;) { int key; cin >> key; if (root == TreeNode::null) { root = new TreeNode(key); } else { root->insert(key); }

20 Chakrabarti Definition of the tree node struct TreeNode { const int key; TreeNode *left, *right; TreeNode(int _key) : key(_key) { left = right = null; } void insert(int nKey) { // while satisfying property } };

21 Chakrabarti insert, first cut if (nKey < key) { if (left == null) { left = new TreeNode(nKey); } else { left->insert(nKey); } else { // repeat above, right instead of left } Tedious, can be avoided if you have a good understanding of * and &

22 Chakrabarti void insert(int nKey) TreeNode*& child = nKey < key? left : right; if (child == null) { child = new TreeNode(nKey); } else { child->insert(nKey); } child is a reference to a pointer to a TreeNode Recursive call from child node

23 Chakrabarti How to print the keys in order void print() { if (left != null) left->print(); cout << key << ' '; if (right != null) right->print(); } main() { if (root != null) root->print(); cout << endl; } 1 2 3

24 Chakrabarti Adding a parent pointer  Walking down from parent to child is easy  Sometimes handy to be able to walk up from child to parent as well, e.g., to find siblings  root->up is null struct TreeNode { const int key; TreeNode *left, *right, *up; TreeNode(int _key, TreeNode *_up) : key(_key), up(_up) { left = right = null; } void insert(int nKey) { … } };

25 Chakrabarti Constant pointer vs. pointer to constant  Suppose we want the up pointer to be constant  This is declared as TreeNode * const up;  Content of TreeNode can change  A pointer to a constant TreeNode would be const TreeNode * up;  Not the same!  Can also have const TreeNode * const up;

26 Chakrabarti Pointers vs. references int a = 3, b = 5; int *px = &a; px = &b; // above statements do not // change values in cells // called a and b int &rx = a; rx = b; // this results in a = b = 5

27 Chakrabarti Multiple pointers to one record  Generally necessary in applications  E.g., fixed deposit accounts and checking accounts pointing to shared customer record  Care is needed in destructors  Deleting a checking account should not destroy a customer record  Should deleting the last account of a customer delete the customer record?  Clear “home” collection whose destruction deletes customer record


Download ppt "Memory Management CS101 2012.1. Chakrabarti Variable storage thus far  Never used global variables  All variables allocated inside functions, passed."

Similar presentations


Ads by Google