Dynamic Memory Allocation

Slides:



Advertisements
Similar presentations
Object Oriented Programming COP3330 / CGS5409.  C++ Automatics ◦ Copy constructor () ◦ Assignment operator =  Shallow copy vs. Deep copy  DMA Review.
Advertisements

Informática II Prof. Dr. Gustavo Patiño MJ
1 Pointers A pointer variable holds an address We may add or subtract an integer to get a different address. Adding an integer k to a pointer p with base.
Review of pointers and dynamic objects. Memory Management  Static Memory Allocation  Memory is allocated at compiling time  Dynamic Memory  Memory.
Pointers. Addresses in Memory When a variable is declared, enough memory to hold a value of that type is allocated for it at an unused memory location.
Review on pointers and dynamic objects. Memory Management  Static Memory Allocation  Memory is allocated at compiling time  Dynamic Memory  Memory.
1 Pointers, Dynamic Data, and Reference Types Review on Pointers Reference Variables Dynamic Memory Allocation –The new operator –The delete operator –Dynamic.
1 Chapter 9 Pointers. 2 Topics 8.1 Getting the Address of a Variable 8.2 Pointer Variables 8.3 Relationship Between Arrays and Pointers 8.4 Pointer Arithmetic.
1 Procedural Concept The main program coordinates calls to procedures and hands over appropriate data as parameters.
Review of C++ Programming Part II Sheng-Fang Huang.
Object Oriented Programming COP3330 / CGS5409.  Dynamic Allocation in Classes  Review of CStrings.
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look.
Pointer Data Type and Pointer Variables
Prof. amr Goneid, AUC1 CSCE 110 PROGRAMMING FUNDAMENTALS WITH C++ Prof. Amr Goneid AUC Part 10. Pointers & Dynamic Data Structures.
Addresses in Memory When a variable is declared, enough memory to hold a value of that type is allocated for it at an unused memory location. This is.
This set of notes is adapted from that provided by “Computer Science – A Structured Programming Approach Using C++”, B.A. Forouzan & R.F. Gilberg, Thomson.
Computer Science and Software Engineering University of Wisconsin - Platteville 2. Pointer Yan Shi CS/SE2630 Lecture Notes.
Pointers OVERVIEW.
C++ Data Types Structured array struct union class Address pointer reference Simple IntegralFloating char short int long enum float double long double.
C++ Programming: From Problem Analysis to Program Design, Second Edition Chapter 13: Pointers You are not responsible for virtual functions (starting on.
Object-Oriented Programming in C++
More C++ Features True object initialisation
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
Object Oriented Programming COP3330 / CGS5409.  Aggregation / Composition  Dynamic Memory Allocation.
1 Recall that... char str [ 8 ]; str is the base address of the array. We say str is a pointer because its value is an address. It is a pointer constant.
1 Chapter 15-1 Pointers, Dynamic Data, and Reference Types Dale/Weems.
Dynamic Memory Management & Static Class Members Lecture No 7 Object Oriented Programming COMSATS Institute of Information Technology.
Chapter 12: Pointers, Classes, Virtual Functions, Abstract Classes, and Lists.
Prof. Amr Goneid, AUC1 CSCE 210 Data Structures and Algorithms Prof. Amr Goneid AUC Part R2. Elementary Data Structures.
Topic 5 Addresses, Pointers and Arrays. 2 Objectives (Textbook Chapter 14) You should be able to describe: Addresses and Pointers Pointer Operators Pointer.
Dynamic Storage Allocation
Pointers and Dynamic Arrays
Linked Lists Chapter 6 Section 6.4 – 6.6
Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes
Motivation and Overview
Andy Wang Object Oriented Programming in C++ COP 3330
Object Oriented Programming COP3330 / CGS5409
CSC113: Computer Programming (Theory = 03, Lab = 01)
Pointer Data Type and Pointer Variables II
Pointers Revisited What is variable address, name, value?
Dynamic Memory CSCE 121 J. Michael Moore.
Chapter 10: Pointers Starting Out with C++ Early Objects Ninth Edition
CSCE 210 Data Structures and Algorithms
8 Pointers.
Pointers and Dynamic Variables
Andy Wang Object Oriented Programming in C++ COP 3330
Dynamically Allocated Memory
Dynamic Memory Allocation
Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes
Automatics, Copy Constructor, and Assignment Operator
Object Oriented Programming COP3330 / CGS5409
understanding memory usage by a c++ program
Pointers and dynamic objects
Chapter 15 Pointers, Dynamic Data, and Reference Types
Automatics, Copy Constructor, and Assignment Operator
Pointers, Dynamic Data, and Reference Types
Chapter 15 Pointers, Dynamic Data, and Reference Types
Given the code to the left:
7 Arrays.
Arrays an array of 5 ints is filled with 3,2,4,1,7
9-10 Classes: A Deeper Look.
Dynamic Objects.
Dynamic Memory.
Recitation Course 0603 Speaker: Liu Yu-Jiun.
COP 3330 Object-oriented Programming in C++
COP 3330 Object-oriented Programming in C++
Pointers and References
Dynamic Memory CSCE 121.
Pointers, Dynamic Data, and Reference Types
9-10 Classes: A Deeper Look.
Presentation transcript:

Dynamic Memory Allocation Andy Wang Object Oriented Programming in C++ COP 3330

Allocation Memory Compile time (or static) allocation Memory for the named variables is allocated by the compiler The exact size and type of storage must be known The array size has to be constant Dynamic memory allocation Memory allocated during run time, placed in a program segment known as the heap or the freestore The compiler does not need to know the exact size and number of items to be allocated Pointers are crucial

Dynamic Memory Allocation Can allocate memory at run time But, cannot create new variables names at run time Thus, there are two steps in dynamic allocation Allocate the space Store its address in a pointer (so that the space can be accessed) Use the new operator

Deallocation Free up the allocated space Compile time (automatic) variables are automatically deallocated A programmer needs to free up dynamically allocated memory Use the delete operator

Allocating Space with new To allocate space dynamically, use the unary operator new, followed by the type being allocated new int; new double; new int[40]; // dynamically allocates an array of 40 ints new double[n]; // dynamically allocates an array of n // doubles, where n can be a variable

Allocating Space with new new by itself allocates spaces with no names new returns the starting address of the allocated space, which can be stored in a pointer int *p; // declares a pointer p p = new int; // dynamically allocate an int and store its // address into p int x = 40; int *list = new int[x]; float *numbers = new float[x + 10];

Accessing Dynamically Allocated Space For single items, dereference the pointer to reach dynamically created target int *p = new int; *p = 10; // assigns 10 to the dynamic integer cout << *p; // prints 10 For dynamically created arrays, you can use either pointer-offset notation, or standard bracket notation double *numList = new double[size]; for (int i = 0; i < size; i++) numList[i] = 0; numList[5] = 20; *(numList + 7) = 15; // same as numList[7]

Stack vs. Heap vs. Content int main() { int *a, *b, *c; a = new int; b = new int; c = new int; *a = 1; *b = 2; *c = 3; cout << "stack: &a: " << &a << " &b: " << &b << " &c: " << &c << endl; cout << "heap: a: " << a << " b: " << b << " c: " << c << endl; cout << "content: *a: " << *a << " *b: " << *b << " *c: " << *c << endl; return 0; } an integer *b = content b = a heap address b &b = a stack address

Deallocation of Dynamic Memory Use unary operator delete int *ptr = new int; delete ptr; // free up the space pointed by ptr Note that the name ptr can be reused ptr = new int[10];

Deallocation of Dynamic Memory To deallocate a dynamic array, use this form delete [] name_of_pointer Example int *list = new int[40]; delete [] list; // deallocates the array list = 0; // reset the pointer to null We don’t want list to point to deallocated space

Suppose… You fail to deallocate dynamically allocated memory… list = new int[40]; // first allocation …// no deallocation… list = new int[10]; // second allocation Result… Memory leak…

Dynamically Resizing an Array Suppose you want to grow an array int *list = new int[size]; int *temp = new int[size + 5]; // create a bigger temp array for (int i = 0; i < size; i++) temp[i] = list[i]; // copy the data delete [] list; // free up the old memory location list = temp; // make list point to the new memory location

Dynamic Allocation of Objects Objects can be dynamically allocated as well Fraction *fp1, *fp2, *flist; fp1 = new Fraction; // uses default contructor fp2 = new Fraction(3,4); flist = new Fraction[20]; // dynamic array of 20 Fraction // objects with default constructor used for each To deallocate delete fp1; delete fp2; delete [] flist;

Dot Operator vs. Arrow Operator A dot operator requires an object name objectName.memberName // member can be data or func An arrow operator works with object pointers objectPointer->memberName

Dot Operator vs. Arrow Operator You need to dereference an object pointer before using the dot operator (*fp1).Show(); An arrow operator is a nice shortcut fp1->Show();

Dot Operator vs. Arrow Operator For pointers to dynamically allocated objects, the arrow operator is easiest ftp->Show(); For pointers to dynamically allocated arrays of objects, arrow operator usually is not needed flist[3].Show(); // flist is a pointer; flist[3] is an object flist[3]->Show(); // INCORRECT

Using Dynamic Allocation inside Classes A motivation example Suppose we want an array as a member data Don’t want a fixed upper bound on the size How to embed a dynamic array inside a class Which can be created statically… Which means compiler needs to know the size in advance…

Solution Only embed the array pointer Declare array pointers as member data Always initialize pointers in the constructor The constructor might dynamically allocate spaces (via new) and assign them to points Or, initialize pointers to null Cleanup (via delete) dynamically allocated space when done using it Can happen in a regular member function Should happen in the destructor, the last function being run before an object is deallocated

Tips Separate memory management tasks from the functionality/algorithmic tasks wherever possible Write member functions just for dealing with memory (allocation, deallocation, resize) Algorithmic functions call the memory handling functions More uses of new and delete, more likely to have a memory leak

Exampe: PhoneBook Database Two classes that use dynamic memory allocation Entry class Represents a single entry in a phone book Uses strings (null-terminated character arrays) to store names, addresses, and phone numbers Directory class Stores a list of Entry objects in a dynamic array Provides services Add, delete, modify, search, and display entries Dynamically resize the array of Entries if needed

entry.h class Entry { public: Entry(); void Load(); // load data into an entry void Show() const; const char*GetName() const; private: char name[20]; phoneNumber[20]; address[20]; };

entry.cpp #include <iostream> #include <cstring> #include “entry.h” using namespace std; Entry::Entry() { strcpy(name, “ “); strcpy(phoneNumber, “ “); strcpy(address, “ “); }

entry.cpp void Entry::Load() { cout << “\nType name, followed by ENTER: “; cin.getline(name, 20); cout << “\nType phone number, followed by ENTER: “; cin.getline(phoneNumber, 20); cout << “\nType address, followed by ENTER: “; cin.getline(address, 20); }

entry.cpp Null-terminated string void Entry::Show() { int i; cout << ‘\t’ << name; for (i = strlen(name) + 1; i < 20; i++) cout.put(‘ ‘); cout << ‘\t’ << phoneNumber; for (i = strlen(phoneNumber) + 1; i < 20; i++) cout.put(‘ ‘); cout << ‘t’ << address; cout << endl; } const char* Entry::GetName() const { return name; Print blanks to format the output

directory.h #include “entry.h” class Directory { public: Directory(); // setup empty directory of entries ~Directory(); // deallocate the entry list void Insert(); // insert a new entry void Lookup() const; void Remove(); void Update(); void DisplayDirectory() const; private: int maxSize, currentSize; Entry *entryList; void Grow(); // increase maximum size // return an index, given name int FindName(char *aName) const; };

directory.cpp #include <iostream> #include <cstring> #include “directory.h” using namespace std; Directory::Directory() { maxSize = 5; currentSize = 0; entryList = new Entry[maxSize]; } Directory::~Directory() { delete [] entryList; }

directory.cpp void Directory::Insert() { if (currentSize == maxSize) Grow(); entryList[currentSize++].Load(); }

directory.cpp void Directory::Lookup() const { char aName[20]; cout << “\tType the name to be looked up, followed by ENTER: “; cin.getline(aName, 20); int thisEntry = FindName(aName); if (thisEntry == -1) { cout << aName << “ not found\n”; } else { cout << “\nEntry found: “; entryList[thisEntry].Show(); }

directory.cpp void Directory::Remove() { char aName[20]; cout << “\nType name to be removed, followed by ENTER: “; cin.getline(aName, 20); int thisEntry = FindName(aName); if (thisEntry == -1) { cout << aName << “ not found”; } else { // shift entries down by one position for (int j = thisEntry +1; j < currentSize; j++) entryList[j – 1] = entryList[j]; currentSize--; cout << “Entry removed.\n”; }

directory.cpp void Directory::Update() { char aName[20]; cout << “\nPlease enter the name of the entry to be modified: “; cin.getline(aName, 20); int thisEntry = FindName(aName); if (thisEntry == -1) { cout << aName << “ not found”; } else { cout << “\nCurrent entry is: \n”; entryList[thisEntry].Show(); cout << “\n”Replace with new entries as follows: \n”; entryList[thisEntry].Load(); }

directory.cpp void Directory::DisplayDirectory() const { if (currentSize == 0) { cout << “\nCurrent directory is empty.\n”; return; } cout << “\n\t***NAME***\t\t***PHONE***\t\t***ADDRESS***\n\n”; for (int j = 0; j < currentSize; j++) { entryList[j].Show();

directory.cpp void Directory::Grow() { maxSize = currentSize + 5; Entry *newList = newEntry[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; delete [] entryList; entryList = newList; } Int Directory::FindName(char *aName) const { if (strcmp(entryList[j].GetName(), aName) == 0) return j; return -1;

menu.cpp #include <cctype> // for toupper #include <iostream> #include “directory.h” using namespace std; void ShowMenu() { cout << "\n\t\t*** PIP 6 PHONE DIRECTORY ***"; cout << "\n\tI \tInsert a new entry into the directory"; cout << "\n\tL \tLook up an entry"; cout << "\n\tR \tRemove an entry"; cout << "\n\tU \tUpdate an entry"; cout << "\n\tD \tDisplay the entire directory"; cout << "\n\t? \tDisplay this menu"; cout << "\n\tQ \tQuit"; }

menu.cpp char GetAChar(const char *promptString) { char response; cout << promptString; cin >> response; response = topper(response); cin.get(); return response; } char Legal(char c) { return ((c == 'I') || (c == 'L') || (c == 'R') || (c == 'U') || (c == 'D') || (c == '?') || (c == 'Q'));

menu.cpp char GetCommand() { char cmd = GetChar(“\n\n>”); while (!Legal(cmd)) { cout << “\nIllegal command, please try again…”; ShowMenu(); cmd = GetAChar(“\n\n>”); } return cmd;

menu.cpp int main() { Directory d; ShowMenu(); char command; do { command = GetCommand(); switch(command) { case ‘I’: d.Insert(); break; case ‘L’: d.Lookup(); break; case ‘R’: d.Remove(); break; case ‘D’: d.DisplayDirectory(); break; case ‘?’: ShowMenu(); } } while (command != ‘Q’); return 0;

Bad Example stack (high address) int main() { … main heap (low address)

Bad Example stack (high address) int main() { Directory d; … main int maxSize = 5 int curentSize = 0 Entry *entryList = d Entry[5] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … main int maxSize = 5 int curentSize = 5 Entry *entryList = d Entry[5] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); void Directory::GrowBad() { main int maxSize = 5 int curentSize = 5 Entry *entryList = d GrowBad() this = Entry[5] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); void Directory::GrowBad() { maxSize = currentSize + 5; main int maxSize = 10 int curentSize = 5 Entry *entryList = d GrowBad() this = Entry[5] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); void Directory::GrowBad() { maxSize = currentSize + 5; Entry newList[maxSize]; main int maxSize = 10 int curentSize = 5 Entry *entryList = d GrowBad() this = Entry newList[10] Entry[5] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); void Directory::GrowBad() { maxSize = currentSize + 5; Entry newList[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; main int maxSize = 10 int curentSize = 5 Entry *entryList = d GrowBad() this = Entry newList[10] Entry[5] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); void Directory::GrowBad() { maxSize = currentSize + 5; Entry newList[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; delete [] entryList; main int maxSize = 10 int curentSize = 5 Entry *entryList = d GrowBad() this = Entry newList[10] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); void Directory::GrowBad() { maxSize = currentSize + 5; Entry newList[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; delete [] entryList; entryList = newList; } main int maxSize = 10 int curentSize = 5 Entry *entryList = d GrowBad() this = Entry newList[10] heap (low address)

Bad Example stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.GrowBad(); main int maxSize = 10 int curentSize = 5 Entry *entryList = d heap (low address)

Visualize the Execution stack (high address) int main() { … main heap (low address)

Good Example stack (high address) int main() { Directory d; … main int maxSize = 5 int curentSize = 0 Entry *entryList = d Entry[5] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … main int maxSize = 5 int curentSize = 5 Entry *entryList = d Entry[5] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); void Directory::Grow() { main int maxSize = 5 int curentSize = 5 Entry *entryList = d Grow() this = Entry[5] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); void Directory::Grow() { maxSize = currentSize + 5; main int maxSize = 10 int curentSize = 5 Entry *entryList = d Grow() this = Entry[5] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); void Directory::Grow() { maxSize = currentSize + 5; Entry *newList = newEntry[maxSize]; main int maxSize = 10 int curentSize = 5 Entry *entryList = d Grow() this = Entry *newList = Entry[10] Entry[5] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); void Directory::Grow() { maxSize = currentSize + 5; Entry *newList = newEntry[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; main int maxSize = 10 int curentSize = 5 Entry *entryList = d Grow() this = Entry *newList = Entry[10] Entry[5] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); void Directory::Grow() { maxSize = currentSize + 5; Entry *newList = newEntry[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; delete [] entryList; main int maxSize = 10 int curentSize = 5 Entry *entryList = d Grow() this = Entry *newList = Entry[10] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); void Directory::Grow() { maxSize = currentSize + 5; Entry *newList = newEntry[maxSize]; for (int j = 0; j < currentSize; j++) newList[j] = entryList[j]; delete [] entryList; entryList = newList; } main int maxSize = 10 int curentSize = 5 Entry *entryList = d Grow() this = Entry *newList = Entry[10] heap (low address)

Visualize the Execution stack (high address) int main() { Directory d; d.Insert(); // 5 times … d.Grow(); main int maxSize = 10 int curentSize = 5 Entry *entryList = d Entry[10] heap (low address)

Note The destructor in Directory is responsible to free up the dynamically allocated Entry array When an object is automatically deallocated, only the space occupied by the object is deallocated Dynamically allocated memory is outside of the object, pointed by the pointer Need to be explicitly deallocated

Another Phonebook Example Uses operator<< and >> instead of Show() and Load()