1 / 56

Pointers and Dynamic Memory

Learn about pointer variables, dynamic memory allocation, address manipulation, and various pointer types in C++. Understand the principles, syntax, and manipulation techniques of pointers.

Download Presentation

Pointers and Dynamic Memory

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Pointers and Dynamic Memory • Pointer variables are necessary for creation and manipulation of dynamic objects • Objects whose memory is acquired during program execution. Dynamic objects stay allocated for the duration na program executes unless deallocated explicitly • Dynamic objects enable variable-sized arrays (lists) • A pointer is an object containing the address of another object • a pointer type specifies the type of objects to be referenced

  2. Pointers Syntax • Example of uninitialized pointers int *iPtr; //iPtr is a pointer to type int char *s; //s is a pointer to type char Date *dPtr; //dPtr is a pointer to type Date & is the address of operator applied to an object, it returns the address (memory location) of the object • Example of initialized pointers int i =1; char c = 'y'; int *iptr = &i; //iptr is points to variable i char *t = &c; // t points to a variable c

  3. Addressing and Indirection • The unary address operator &can be used to obtain the address of an object • The indirection or dereferencing operator *, when used on a pointer object, computes the lvalue of the object to which the pointer object points.

  4. Example of Pointer Manipulation #include <iostream> using namespace std; int main() { int v1, *ptr1 = &v1, v2, *ptr2 = &v2, *ptr3 = 0; cout << "Enter two integers: "; cin >> v1 >> v2; *ptr1 += v2; (*ptr2)++; // * has lower precedence than ++ ptr3 = ptr2; ptr2 = ptr1; *ptr1 = v1 + *ptr3; cout <<"v1 = " << v1 << " v2 = " << v2 << endl; cout <<"*ptr1 = " << *ptr1 << " *ptr2 = " << *ptr2 << endl; cout <<"*ptr3 = " << *ptr3 << endl; return 0;}

  5. Pointers(1) C++ allows pointer types whose objects are pointers to pointers to pointers, and so on. int **ptrptr; // ptrptr is a pointer to type int* int i = 0; int *ptr = &i; ptrptr = &ptr; // OK! because ptr is an int* ptrptr = ptr; // Illegal! ptrptr needs an int**

  6. Pointers(2) Pointers as parameter Functions can have pointer type parameters. void indirectSwap(int* ptr1, int *ptr2){ int temp; temp = *ptr1; *ptr1 = *ptr2; *ptr2 = temp; } Call: int v1, v2; // ... indirectSwap(&v1, &v2);

  7. Pointers(3) Constant pointers and pointers to constants The modifier const can be applied in pointer definitions; depending on where the modifier const is placed, either the pointer is a constant or the contents of the location to which the pointer points are considered to be constant. char c1 = 'a'; char c2 = 'b'; const char *cPtr1 = &c1; // *cPtr1 is considered to be //constant! cPtr1 is not a const char const *cPtr2 = &c2; // *cPtr2 is considered to be //constant! cPtr2 is not a const char *const cPtr3 = &c1; // cPtr3 is constant; *cptr3 is // not constant

  8. Pointers(4) Constant pointers and pointers to constants (contd.) *cPtr1 = 'A'; // illegal: *cPtr1 is a constant! c1 = 'A'; // legal: c1 is not a constant! cPtr3 = cPtr2; // illegal; cPtr3 is a constant; const char* const cPtr4 = &c1; // *cPtr4 is (considered) // const and cPtr4 is constant

  9. Arrays and Pointers In C++ the name of an array is considered to be a constant pointer; as soon as an array name occurs in an expression, there is an automatic type conversion to a pointer, and the pointer will point to the first element in the array.\ int intArr[] = {1, 2, 3, 4}; int *intPtr = intArr; // intArr is same as &intArr[0] cout << *(intPtr+2) << endl;// outputs intArr[2]

  10. C-style character strings text strings are stored as arrays of characters terminated by null character ’\0’ char txt[5]; char name[] = "Sara";// 5-element char array char *charPtr; charPtr = name; // charPtr points to name[0] cout << charPtr << endl; // "Sara" is written cout << charPtr+2 << endl; // "ra" is written cout << *(charPtr+2) << endl; // "r" is written \end{verbatim}

  11. Array of Pointers int main() { char *message[] = {"Enter an integer", "Input Error", "Error: divide by zero", "You have mail"}; for (int i = 0; i < 4; i++) cout << message[i] << endl; }

  12. C-style Character Strings There is a c-style string library cstring which contains various functions for processing null terminated string: #include <cstring> // or #include <string.h> strcpy(s1, s2); // copies s2 to s1 strcat(s1, s2); // puts a copy of s2 at the end of // s1; no checks for space is done strlen(s); // returns the length of the string s // (excluding '\0') // ...

  13. Pointers and Free Store Memory class of an object may be one of the following Static: Memory is allocated once at the beginning of execution and stays allocated until the program terminates. Example: global and static local variables. Automatic: Memory is allocated when the block of declaration is entered and deallocated each time the block is exited. Example: local variables and parameters. Dynamic: Memory is allocated from the free store (heap), using operator new and stays allocated during the execution until it is de-allocated using operator delete

  14. Dynamic Memory Dynamic objects can be referred to only via pointers. int *iPtr; // iPtr is uninitialized iPtr = new int; // iptr points to an int // object (no value yet) *iPtr = 10; // the object pointed to by // iPtr receives the value 10 cout << *iPtr << endl; delete iPtr; // return the memory to the // operating system; iPtr is // undefined

  15. General new Operation Behavior • Memory for dynamic objects is requested from the free store. • Free store is memory controlled by the operating system. • Operation specifies the type and number of objects • If there is sufficient memory to satisfy the request, a pointer to the memory is returned by the operation • If there is insufficient memory to satisfy the request, an exception is generated (an error state/ condition which if not handled (corrected) causes the program to terminate) Syntax Ptr = new SomeType ; where Ptr is a pointer of type SomeType The newly acquired memory is uninitialized unless there is a default constructor for the class SomeType

  16. The new Operator • SomeType *Ptr = new SomeType( argumentList); The newly acquired memory is initialized using appropriate SomeType constructor. int *iptr = new int( 10); Date *birthDate = new Date(1995, 8, 13); • someType *P = new SomeType [Expression]; where Expression is the number of contiguous objects of type SomeType to be constructed. Example: int *iArray = new int [3];

  17. delete Operator delete operator is used to return dynamic memory to the free store delete P; //return storage that was obtained by //a call to new delete [] P; //return storage that was obtained by //a call to new[] Returnsstorage pointed to by pointer P is returned to free store; P is now undefined

  18. Pointers and Class type A class cannot have self-reference except via a pointer or reference type class Employee { public: Employee(...); ... private: char *name; // a member of pointer type unsigned id; Employee *manager; // self-reference via pointer double salary; }; Note: Member-wise copy semantics may not be desirable if any data member is a pointer

  19. flexarray: A Flexible dynamic array class Define a class to implement a flexible array type • The size of the array can grow and shrink at runtime • Array element access by operator[] is checked for valid index range • The lowest index of the array can be any user set value (C++ arrays always begins with index 0)

  20. Class flexarray(1) • Make the constructor explicit. This will disallow a typically erroneous implicit type-conversion: flexarray a( 10 ); a = 0; // Oops!! Allowed because of // implicit type-conversion. • An explicit member function is needed for each of a) copy constructor b) destructor c) copy assignment operator

  21. Class flexarray class flexarray { public: // Constructor that can specify size, intialization // value and lowest index explicit flexarray( int size=0, const int &fillValue=0, int lb=0); // copy constructor flexarray( const flexarray & fla ); // destructor ~flexarray( ); // other member functions private: int mySize; // # elements in array int * myList; // array used for storage int lower; // lower bound of index };

  22. Constructor(s) for flexarray This constructor has three parameters and each can take default value so that there are four possible ways of creating an object using none, one, two, or all three of the default values flexarray::flexarray(int size, const int &fillValue, int lb) // precondition: size >= 0 // postcondition: flexarray has a capacity of size items, // all of which are set by assignment to fillValue / after default construction : mySize(size), myList(new int[size]), lower(lb){ int k; for(k = 0; k < size; k++) { myList[k] = fillValue; } }

  23. Member initialization list • Alternative syntax for the initialization of a class member • It is a comma-separated list of a member name and its initial value • The member initialization list can only be specified within the constructor definition, not its declaration: className::className(parameter list) initialization list {function body} where initialization list has the following form: :d1(expression), d2(expression), ...,dn(expression) where d1, d2, ..., dn are names of data members • References and constants must be initialized with the initialization list

  24. Copy Constructor • Has a parameter that is a reference to another object of the same class • Is called automatically if there are declarations of the form: CT obj1=obj2; CT obj1(obj2); where CT is a class type and obj1 and obj2 are objects of type CT flexarray::flexarray(const flexarray & fla) // postcondition: flexarray object is a copy of fla : mySize(fla.length()), myList(new int[mySize]), lower(fla.lbound()) { int k; // copy elements for(k = 0; k < mySize; k++){ myList[k] = fla.myList[k]; } }

  25. Assignment Operator const flexarray & flexarray::operator = (const flexarray &rhs) // postcondition: normal assignment via copying has been // performed; if flexarray object and rhs were different sizes, then flexarray object // has been resized to match the size of rhs { if (this != &rhs) // don't assign to self! { delete [] myList;// get rid of old storage mySize = rhs.length(); lower = rhs.lbound(); myList = new int [mySize]; //allocate new storage // copy rhs int k; for(k=0; k < mySize; k++) myList[k] = rhs.myList[k]; return *this; // permit a = b = c = d }

  26. Upper and Lower Index int flexarray::ubound() const{ // postcondition: returns flexarray's upper index bound return (lower+mySize-1); } int & flexarray::operator [] (int k) { // description: range-checked indexing, returning item at k // precondition: lower <= k <= lower+mySize-1 // postcondition: returns item at position k if (k < lower || k >= (lower+mySize)){ cerr << "Illegal flexarray index: " << k << endl; if ( k < lower ) cerr << " min index = " << lower << endl; if (k >= (lower+mySize)) cerr << " max index = " << (lower+mySize-1) << endl; exit(1);} return myList[k-lower]; }

  27. Destructor Member Function The name of the destructor function is the class name preceded by tilde (~) classname::~className(){ //… } Called automatically when a class object leaves its scope to clean up and release resources The Destructor must not be overloaded and may not have any parameter. If not defined, the compiler will supply one. flexarray::~flexarray () // postcondition: flexarray object is destroyed { delete [] myList; }

  28. Index Operator [] (constant return) const int & flexarray::operator [] (int k) const // safe indexing, returning const reference to avoid // modification; return item at k // precondition: lower <= k <= ubound() // postcondition: return item at k // exception: exits if index is out-of-bounds { if (k < lower || k >= (lower+mySize)) { cerr << "Illegal flexarray index: " << k << endl; if ( k < lower ) cerr << " min index = " << lower << endl; if (k >= (lower+mySize)) cerr << " max index = " << (lower+mySize-1) << endl; exit(1); } return myList[k-lower]; }

  29. Resizing flexarray Objects void flexarray::resize(int newSize) // description: resizes the flexarray object to newSize // elements // precondition: the current size of flexarray is length(); // newSize >= 0 // postcondition: the current size of flexarray is newSize; for // each k such that 0 <= k <= min(length, // newSize), flexarray[k] is a copy of the // original; other elements of flexarray are // initialized using the 0-argument int // constructor // Note: if newSize < length, elements may be lost {

  30. Resizing flexarray Objects (contd) { int k; int numToCopy = newSize < mySize ? newSize : mySize; // allocate new storage and copy element into new storage int *newList = new int[newSize]; for(k=0; k < numToCopy; k++) { newList[k] = myList[k]; } delete [] myList; // de-allocate old storage mySize = newSize; // assign new storage/size myList = newList; }

  31. Summary • Many of the C++ operators can be overloaded for class type • Overloading of operator functions provides a natural usage of class objects • Nonmember Functions and classes can be declared “friend” of a class within that class’ definition. A friend function or class has the same access privilege as a member. • An alternative to providing “friend” access is to provide suitable accessor/modifier member functions • We must limit the number of nonmember functions having direct access to the internal implementation of class.

  32. Generic Programming using Function Templates • A function template describes a function format that when instantiated with particulars generates a function definition • A function generated from a function template is called a template function template<class T> Type funcName (//list of parameters of which at // least one is of type T) { function body }

  33. Generic Programming using Function Templates (contd.) • Based on the argument types in calls, the compiler generates a template function with appropriate types • The formal type parameters are built-in or user-defined types • Every type parameter in template definition must appear in the functions parameter list at least once!

  34. Example of Function Templates #include <iostream> using namespace std; template <class T> T min( T a, T b ){//works for any type for which //comparison ‘<‘ is defined return a < b ? a : b; } int main(){ // creates int min( int, int ); cout << "minimum of 10 and 20 is: " << min( 10, 20 ) << endl; // creates double min( double, double ); cout << "minimum of 10.3 and 20.6 is: " << min( 10.3, 20.6 ) << endl; return 0; }

  35. Generic Types: Class Templates Templates enable us to specify a range of related functions called template functions, or a range of related classes called template classes Class templates provide the means for describing a class generically and instantiating classes that are type-specific versions of this generic class Example: flexarray class of integers, doubles, fractions, dates, … share a common interface and data structure and differ only by the type of the elements they contain.

  36. Class Templates Defining a template class template <class T> // class definition class C { // ... returnType f(parameters); // … private: T data; //... }; template <class T> // member function definition returnType C<T>::f(parameters){ ... } • T is a type parameter and is used as an ordinary type inside the class • Instances of class are created when we write C <typename> then T is replaced by typename everywhere in this instance. The expression C<typeName> can be used as an ordinary class name • Type parameters are place holders and specify information needed to instantiating the template class (the compiler generates the necessary code)

  37. flexarray Template class template <class T> // flexarray is a template class class flexarray { public: // Constructor that can specify size, intialization // value and lowest index; note type T of the elements. // Class T assumed to have a default constructor explicit flexarray( int size=0, const T &fillValue = T(), int lb=0); //A copy constructor flexarray( const flexarray<T> & fla ); ~flexarray( ); // destructor // Assignment operator const flexarray & operator = ( const flexarray<T> & fla );

  38. flexarray Template class (1) // accessors int length( ) const; // size of flexarray int lbound() const; // lowest index int ubound() const; // highest index // indexing T & operator [ ] ( int index ); const T & operator [ ] ( int index ) const; // modifiers void resize( int newSize ); // change size dynamically; private: int mySize; // # elements in array T * myList; // stores objects of type T int lower; // lower bound of index };

  39. flexarray Template class (2) template <class T> flexarray<T>::flexarray(int size, const T &fillValue, int lb) // precondition: size >= 0. Class T has a default constructor. // postcondition: flexarray has a capacity of size items, all // of which are set by assignment to fillValue after default // construction : mySize(size), myList(new T[size]), lower(lb) { int k; for(k = 0; k < size; k++) { myList[k] = fillValue; } }

  40. flexarray Template class (3) template <class T> flexarray<T>::flexarray(const flexarray<T> & fla) // precondition: Class T has overloaded assignment // operator // postcondition: flexarray object is a copy of fla : mySize(fla.length()), myList(new T[mySize]), lower(fla.lbound()) { int k; // copy elements for(k = 0; k < mySize; k++){ myList[k] = fla.myList[k]; } }

  41. flexarray Template class (4) template <class T> T & flexarray<T>::operator [] (int k){ // description: range-checked indexing, returning item at // index k // precondition: 0 <= k < length() // postcondition: returns the kth item if (k < lower || k >= (lower+mySize)){ cerr << "Illegal flexarray index: " << k << endl; if ( k < lower ) cerr << " min index = " << lower << endl; if (k >= (lower+mySize)) cerr << " max index = " << (lower+mySize-1) << endl; exit(1); } return myList[k-lower]; }

  42. Template Class Properties • Template Classes and Friends: - A template class can have friends that are templates with the same ordifferent type parameters, or non-templates • Templates and Static Members: - Each template class has its own copy of static members - Static data members must be initialized at the file scope. static data member v in class C will have the definition: template <class T> C<T>::v = initialization value;

  43. Recursive programs • Recursion is the ability of a function to call itself • During execution there are as many instances of the function as the number of non-terminated calls made • Each instance of the function has its own values for formal parameters and local variables Example: The factorial function is defined in terms of itself • 0! = 1 (Base case) • n! = n*(n-1)!, for n >= 1 (Recursive step)

  44. The factorial Function(1) //computeFactorial.cc: Computes factorial of // nonnegative integer //includes ... int factorial(int, unsigned long); int main() { int m; int indent = 0; cout <<"Enter Number for factorial computation--> "; cin >> m; cout << factorial(indent, m) << endl; return 0; }

  45. The factorial Function(2) int factorial(int indent, unsigned long m) { int result; cout << setw(indent) <<"" << "ENTERING factorial() WITH m = ” << m << endl; if ((m == 1) || (m == 0)) { cout << setw(indent) << "" << "LEAVING factorial() WITH m = ” << m; cout << ", factorial() = " << 1 << endl; --indent; return 1; } else { ++indent; result = m * factorial(indent, m-1); --indent; cout << setw(indent) << "" << "LEAVING factorial() WITH m = ” << m; cout << ", factorial() = " << result << endl; return result; } }

  46. The factorial Function(3) A sample run Enter Number for factorial computation--> 5 ENTERING factorial() WITH m = 5 ENTERING factorial() WITH m = 4 ENTERING factorial() WITH m = 3 ENTERING factorial() WITH m = 2 ENTERING factorial() WITH m = 1 LEAVING factorial() WITH m = 1, factorial() = 1 LEAVING factorial() WITH m = 2, factorial() = 2 LEAVING factorial() WITH m = 3, factorial() = 6 LEAVING factorial() WITH m = 4, factorial() = 24 LEAVING factorial() WITH m = 5, factorial() = 120 120

  47. Form of a Successful Recursive Function Base Case: There must always be some base cases in which the computation is accomplished without recursion. Making Progress: For the cases that are to be solved recursively, the recursive call must always be to a case that makes progress toward a base case. Efficiency: Never duplicate work by solving the same instance of a problem in separate recursive calls.

  48. Recursive Problem-solving(1) • Decompose problem into smaller problem of same type • Solve the smaller sub-problems recursively • Combine the solutions of the sub-problems to obtain a solution of the original problem

  49. Recursive Problem-solving(2) • Produces elegant and clean solutions • Valuable when no iterative solution is possible • Introduces bookkeeping overhead that can slow down the program

  50. Recursion vs. Iteration When a recursive call is the last executed statement of the function, the call is said to be tail recursive. Example: Recursive factorial function is tail recursive We can speed up a program by replacing tail recursion by iteration.

More Related