310201 fundamental programming pointers and dynamic memory

72
310201 Fundamental Programming Pointers and Dynamic Memory.

Upload: primrose-bailey

Post on 27-Dec-2015

224 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

310201Fundamental Programming

Pointers and Dynamic Memory.

Page 2: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Topics for this Week : Week 9

• Pointers,• Dynamic Memory,• Memory Addresses,• New and Delete Operations.

Page 3: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Address of Objects - & Operator • All C++ variables occupy memory within

the computer.• All memory locations within the

computer can be accessed by using a unique address to that segment of memory.

• If, for instance, we made the declarations :int i = 8, k = 12;

• then we have declared 2 integers : i and k, and assigned initial values to them.

Page 4: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Address of Objects - & Operator (cont …)

• Remembering the fact that standard integers in C++ require 2 bytes of memory, then the data in memory would look something like this :

Memory Address(Will vary depending

on your PC, setup, etc).

Contents Name/Tag

0x118f2410 8 i

0x118f2412 12 k

Page 5: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Address of Objects - & Operator (cont …)

• C++ allows us to find out the memory address at which an object is located by using a special version of the ampersand & operator.

• WARNING: The ampersand & operator is used in several different roles, for example, it is used in :– Pass by reference operator. i.e. Reference Parameter,– Bitwise AND,– Address of memory variable. i.e. an address of an object.

• You must ensure that you are aware of which particular role the ampersand & operator is playing in the different parts of a program !

Page 6: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Address of Objects - & Operator (cont …)

• An & (ampersand) in front of an object name means “give me the memory address of the object” :int i = 8, k = 12; // Declare and initialise 2 integers.

cout << "Memory address of i = " << &i << endl;cout << "Memory address of k = " << &k <<

endl;

• The output from this program would be something like :Memory address of i = 0x118f2412Memory address of k = 0x118f2410

Page 7: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers• An object that can store the address of another

object is called a pointer.• Pointers are declared by using the asterisk *

operator.

• WARNING: The asterisk * operator can be used in different roles, for example, it is used in :– Multiplication of numbers,– Declaring a pointer, and,– De-referencing operator for pointers (more on this soon).

• You must ensure that you are aware of which particular role the asterisk * operator is playing in the different parts of a program.

Page 8: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer and Address Exampleint i = 8, j =12; // Declare and initialise 2 integers.int *iPtr = &i; // iPtr is a pointer to an integer stored at address

&iint *jPtr = &j; // jPtr is a pointer to an integer stored at address

&j cout << "At address " << iPtr << " which is the same as " << &i<< ", the value " << *iPtr << " is stored." << endl; cout << "At address " << jPtr << " which is the same as " << &j<< ", the value " << *jPtr << " is stored." << endl;

• The output from this program would be something like :At address 0x4e772430 which is the same as 0x4e772430, the value 8 is stored.At address 0x4e77242e which is the same as 0x4e77242e, the value 12 is stored.

Page 9: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer and Address Example (cont …)

• In this example :– Two integers (i and j) are declared and given initial values.– Then, 2 pointers (iPtr and jPtr) are declared - using the

asterisk * operator - and initialised to the addresses - using the ampersand & operator - of the 2 integers (i and j) respectively.

– Then some lines of output are displayed using the pointers, the ampersand & operator, and the asterisk * operator.

• The result of this is that iPtr contains the memory address the address of integer i. And, *iPtr contains the contents or value of the integer i. Similarly for j and jPtr.

Page 10: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer and Address Example (cont …)

• The use of the ampersand & operator and asterisk * operator is very important in this example.

• You cannot use these operators inter-changeability :– &P means the address of a particular

object P. – *P means the contents of memory

pointed to by P.

Page 11: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer and Address Example (cont …)

• Consider the following :Name/Tag Stored in Memory Memory Addressi ===========> 8

0x4e772430*iPtr ========================> 0x4e772430

• where :– i is a direct reference to an address value. i.e. 8. – &i is the address of the value referred to by i. i.e.

0x4e772430.– iPtr contains the address of the value referred to by

i. i.e. 0x4e772430.– *iPtr is the contents of the memory pointed to by

iPtr, which is the contents of the memory location 0x4e772430, which is the value 8 – which, ofcourse, is the value of i.

Page 12: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer De-Referencing

• In other words iPtr is an indirect reference to (in this case) the integer object referred to by i.

• To obtain direct access to an object via an indirect reference we must use the asterisk (*) operator on the indirect reference.

• This is called pointer de-referencing.

Page 13: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers in General• It so happens that the concept of

pointers is probably only exceeded in its importance to modern computing by the concept of Object Oriented Programming (OOP).

• In fact, without pointers, OOP could not be implemented !

• The concept of pointers could be argued as one of the single most important concepts in all of programming.

Page 14: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and Strings • Consider the following pointer declaration :

 char *str_ptr = "HAL"; 

• This places the string "HAL" into an array pointed to by str_ptr, and automatically appends the null terminator ‘\0’ to the end.

• That is :– An array of 4 characters is allocated !– str_ptr points to the start of this array !

Page 15: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and Strings (cont …)

• If we do the following :cout << *str_ptr << endl; 

• then we would see "H" displayed onto the screen only - this is the memory location pointed to by str_ptr pointer.

• Similarly :cout << str_ptr[0] << endl; 

• would also display just the "H" onto the screen, and once again this is the value at index location 0 of the array pointed to by str_ptr.

Page 16: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and Strings (cont …)

• However, the following : cout << str_ptr << endl; 

• would display the entire string "HAL" to the screen, and because we are using cout, output automatically stops at the null terminator ‘\0’.

Page 17: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer De-referencing

• The asterisk (*) operator can be used as a modifier in declaring a pointer.

• It can also be used in a different role to act as a de-referencing operator.

• Before we can obtain direct access to an object via an indirect reference we must perform an operation on the indirect reference called pointer de-referencing.

Page 18: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer De-referencing (cont …)

int num1, num2; // Declare two integers. int *nPtr = &num1; // Declare and initialise an integer

pointer. num1 = 6; // Assigns 6 to num1. num2 = *nPtr; // Assign value of num1 to num2 via pointer de-

referencing. *nPtr = 7; // Assign value 7 to num1 via pointer de-

referencing. cout << "num1 = " << num1 << endl;cout << "num2 = " << num2 << endl;

Page 19: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - Initialisation• We have already seen that a pointer can be

initialised to an address of an existing object. For example :

int num = 2;int *numpointer = &num;

• However, you cannot do this :

double DoubleVar ;int *iPtr = &DoubleVar; // ERROR !!

• This is not valid, because the pointer type must match the type of whatever it points at.

• In this case, iPtr should be of type double like DoubleVar, instead of an int.

Page 20: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Let’s Recap – with some exercises …

• What would be the result of this code :int i;int *My_Ptr;My_Ptr = &i;*My_Ptr = 25;

• Is this code valid ? Why ? int i = 25;int *My_Ptr = i;

Page 21: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - the NULL Address

• It is valid to do this : 

char *cPtr = 0; // Initialise to the NULL addressint *iPtr = NULL;int *kPtr = 0; 

• The NULL (or 0) address is a special value that can be assigned to a pointer to indicate that it is not currently pointing to any particular memory location.

• This is not the same as the pointer variable being undefined. i.e. having no particular value.

Page 22: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - the NULL Address (cont …)

• We can use the NULL memory address to see whether the pointer is defined before using it :

 

int *iPtr = 0;::::: other code to manipulate the pointer 

if (iPtr == 0) // iPtr is not pointing to a memory

locationelse // iPtr is pointing to a memory location

Page 23: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - the NULL Address (cont …)

• Or, instead of 0, we can use the NULL keyword directly : 

int *iPtr = NULL;::::: other code to manipulate the pointer 

if (iPtr == NULL) // iPtr is not pointing to a memory

locationelse // iPtr is pointing to a memory location

Page 24: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - Assignment• As we have already seen, pointers can

be used to assign values to the objects that they point at.

• Once a pointer points at something, it can easily be changed to point at another object of the same type.

• The statement : 

jPtr = iPtr; // Assignment. 

• has the effect of changing the memory address pointed to by jPtr, to the same memory address pointed to by iPtr.

Page 25: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations – Assignment (cont

…)

int i = 8, j =12; // Declare and initialise 2 integersint *iPtr = &i, *jPtr = &j; // Declare and initialise 2 integer pointers

 cout << "Before pointer assignment :" << endl;cout << "\nAt address " << iPtr

<< ", the value " << *iPtr << " is stored" << endl;cout << "At address " << jPtr

<< ", the value " << *jPtr << " is stored" << endl; 

jPtr = iPtr; // Assignment. 

cout << "After pointer assignment :" << endl;cout << "\nAt address " << iPtr

<< ", the value " << *iPtr << " is stored" << endl;cout << "At address " << jPtr

<< ", the value " << *jPtr << " is stored" << endl;

Page 26: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations – Assignment (cont

…)

• The output produced by this code would be something like :Before pointer assignment :At address 0x4faf24ac, the value 8 is storedAt address 0x4faf24aa, the value 12 is stored

After pointer assignment :At address 0x4faf24ac, the value 8 is storedAt address 0x4faf24ac, the value 8 is stored

Page 27: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - Comparison • You may use the relational operators to

compare two pointers as long as they are of the same type.

•  For example, the following comparisons are legal :

if (iPtr == jPtr) // as long as both pointers are same type.

if (iPtr != 0) // check pointer is not pointing to NULL address.

• You can also use of other comparison operators : >, <, >=, <=, etc, but these do not make much sense for pointers, because they contain memory addresses.

Page 28: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Exercise #2 **

• What would be output by this code :int i = 3, k=3;int *iPtr = &i;int *kPtr = &k;

if (iPtr == kPtr)cout << "Same";

elsecout << "Different";

Page 29: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Exercise #3 **

• What would be output by this code :int i = 3, k=3;int *iPtr = &i;int *kPtr = &k;

if (&iPtr == &kPtr)cout << "Same";

elsecout << "Different";

Page 30: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Exercise #4 **

• What would be output by this code :int i = 3, k=3;int *iPtr = &i;int *kPtr = &k;

if (*iPtr == *kPtr) cout << "Same";

elsecout << "Different";

Page 31: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations - Arithmetic

• The various operators such as : ++, --, += , -= may also be used on pointers to enable us to rapidly move through memory locations, but be very careful where you start and finish in memory.

• As with arrays, C++ will not warn or inform you if you go outside the memory locations allowed for the pointer.

Page 32: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Operations – Arithmetic (cont …)

• Here we are initialising an array - without even using the array's name :

double dArray[10];double *dPtr = dArray; // Points to the address of dArray[0]. for(int x = 0; x < 10; x++){ *dPtr = 0.0; // Set elements to zero dPtr++; // Increment memory location pointed at} // to point to next array element. 

Page 33: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Sizeof : Advanced • For pointer arithmetic it is sometimes useful

to know the size of a particular object in memory.

• The C++ sizeof function provides this information.

• For example :sizeof (double); // Would return 8.sizeof (int); // Would return 2 or 4 depending on your // operating system / computer hardware.

• sizeof returns the number of bytes of storage for a particular object or data type.

Page 34: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Sizeof : Advanced (cont …)

• This is also true for arrays :float fArray [20];cout << sizeof (fArray); // Would output 20 x 4 = 80cout << sizeof (fArray) / sizeof (float);// Would output 80 / 4 = 20

• As you can see from this example sizeof (fArray) returns the total number of bytes of memory reserved for the array.

• In order to obtain the number of elements in the array, we need to divide this value by sizeof (float) !

Page 35: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Sizeof : Structures and Arrays of Structures

struct People{

char Name [20]; // 20 characters = 20 bytes of memorychar Address [50]; // 50 characters = 50 bytes of memoryfloat Age; // 4 bytes of memoryint Weight; // 2 bytes of memory

// Total = 76 bytes of memory per object delcared.

}; void main (){

People Village [10]; // Declare array of 10 Peoplecout << sizeof (People); // Would output 76cout << sizeof (Village); // Would output 76 * 10 = 760cout << sizeof (Village) / sizeof (People); // Would output 760 / 76 = 10

}

Page 36: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers, Strings, and (Ptr + i)[k] notation

• As we have seen earlier, this code :char *str_ptr = "Hi There";

• declares array containing the text plus the null terminator '\0', and :cout << *str_ptr << endl;

• would output just a "H". And :cout << str_ptr[0] << endl;

• would also output just a "H".

Page 37: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers, Strings, and (Ptr + i)[k] notation (cont …)

• However :cout << str_ptr[5] << endl;

• would output the contents of location 5 (i.e. the 6th element) in the array. i.e. "e".

• In a similar way :cout << (str_ptr + 3)[2] << endl;

• would jump to the 3rd location in the string / array and then use this as the base of an array and jump to the 2nd location in this array, and this would output the letter "e" to the screen. This has the same effect as : cout << str_ptr[5] << endl;

Page 38: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers - HAL and IBM Example

• Using pointers with array notation :

char *str_ptr = "HAL";

for (int i = 0; i < 3; i++){

str_ptr [i] = str_ptr[i] + 1;}cout << str_ptr << endl;

Page 39: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers - HAL and IBM Example (cont …)

• Or, we could do the same thing using pointers with pointer notation :

char *str_ptr = "HAL";

for (int i = 0; i < 3; i++){

*(str_ptr + i) = *(str_ptr + i) + 1;}cout << str_ptr << endl;

Page 40: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointer Arithmetic and Scaling• Arithmetic operations on pointers are scaled.• That is, when you perform pointer arithmetic,

the compiler scales the result relative to the type of data being pointed to, rather than by bytes of memory.

• Example :float *fPtr; // Floats occupy 4 bytes of memory !!++fPtr;

• The ++fPtr would increment the pointer by one float location. This new memory address will be 4 bytes away from its original location – not one byte !

• It is very important that you remember this scaling aspect of pointers !

Page 41: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Exercise #5 **• If we had :

char *str_ptr = "HAL";

• What would result in each instance below :• cout << *(str_ptr + 0) << endl;• cout << *(str_ptr + 1) << endl;• cout << *(str_ptr + 2) << endl;• cout << *(str_ptr + 3) << endl;• cout << *(str_ptr + 4) << endl;• cout << *(str_ptr - 1) << endl;• cout << *(str_ptr – 15)[17] << endl;• Warning: Be extremely careful when using

pointers !!

Page 42: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and Call by Reference• Pointers can be used to implement a call by

reference parameter passing mechanism.• In fact in C, the precursor of C++, this was the

only method possible of passing parameters !• Function to swap two integer values, and has 2

pointers as parameters : void swap (int *x, int *y){

int temp = *x; // temp = value in x*x = *y; // set x’s value to y’s*y = temp; // set y’s value to x’s original value

}

// Exercise : Why isn't temp a pointer ?

Page 43: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and Call by Reference (cont …)

void main(){

int a = 10;int b = 20;

 swap (&a, &b);   // Exercise : Why use '&' ?

cout << "\na = " << a << ", b = " << b << endl;

}

Page 44: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and Call by Reference (cont …)

void main(){

int a = 10;int b = 20;

 int *p = &a;// Exercise : What's happening here ?int *q = &b;

 swap (p, q);// Exercise : How does this work ??

 cout << "\na = " << a << ", b = " << b << endl;

}

Page 45: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and the New and Delete Operations

• When we allocate memory at compile-time, for example to an array object, we are allocating a fixed amount of memory which cannot be changed during program operation. The only way to change the array's size is to change our source code and re-compile our program. Such arrays are said to be static arrays.

• For example, this code :const int Length = 20;double List [Length];

• declares an array of 20 double length floating point elements, with valid index locations 0 to 19. This array is fixed in size ! i.e a static array !

Page 46: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and the New and Delete Operations (cont …)

• To allow us to dynamically allocate memory (i.e. so we can declare an array of variable size) at run-time, we require the C++ new and delete operations.

• The new operator dynamically allocates or reserves memory and has the form :new <Type of object>

• The new operation returns a pointer and so is used in conjunction with a pointer variable.

• If the request for run-time memory can not be granted then new operation returns the NULL memory address (i.e. zero), otherwise it allocates a block of memory large enough to hold the required object(s), and returns a pointer to the start of this allocated memory.

Page 47: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and the New and Delete Operations (cont …)

• When we declare a pointer that does not point to an existing object, then all this pointer can hold is a memory address, it cannot be used to store any real data until the new operation has been used.

• Also, when we use the new operation, we should check the pointer's value to see if the memory allocation was successful.

Page 48: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and the New and Delete Operations (cont …)

double *dPtr; // Define a Pointer of type double. Uses no memory !

 dPtr = new double; // Allocate 8 bytes of memory. i.e.

sizeof(double). if (dPtr == 0) // Was the memory allocated successfully ?{

cerr << "\n*** Out of Memory!\n"; // No !exit(-1); // Exit the program.

} cout << "\nEnter a double float value : ";cin >> *dPtr; // Dereference Ptr to store an input value.cout << "\nYou entered : " << *dPtr; // Dereference Ptr to display

value.

Page 49: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and the New and Delete Operations (cont …)

• Since we do not have an inexhaustible amount of dynamic memory to allocate from the free store or heap we should always reclaim or unallocate any previously reserved memory when it is no longer required, and this can be done using the delete operation.

• For example, we could reclaim / unallocate the memory previously allocated, via the new operation above, using the following :delete dPtr; // Deallocate memory reserved earlier.

Page 50: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Pointers and the New and Delete Operations (cont …)

• If we try and use or dereference the pointer after this delete operation, such as :cout << *dPtr;

• then unpredictable results may occur. For example, you could access memory no longer reserved by this program and cause a system crash.

• It is good practice to set the pointer to NULL memory address (i.e. zero) after the delete operation :delete dPtr; // Reclaim the memory.dPtr = 0; // Point to the Null - for safety !

• and then test that the pointer does not point to zero before using it.

Page 51: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Memory Leaks• If you do not deallocate memory that you have

previously reserved, and the program exits, then the memory will remain allocated – even after the program has ended !

• Such a program is said to have a memory leak.• If you repeatedly run the program (which allocates

memory but does not unallocate it), then more and more of your computers free memory will be reserved. Eventually, your computer will run out of free memory, and the program will not be able to run at all.

• Memory leaks are the sign of sloppy or careless work.

• Always ensure your programs have no memory leaks.

Page 52: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Structure Pointer : Indirect Component Selection Operator (->)• In C++ there is another operator, called the

indirect component selection operator (->) which combines the functionality of the pointer dereferencing operator (*) and the dot component selection operator (.).

• A common name for the indirect component selection operator (->) is the arrow.

• Let's see this in action :struct Student_Record{

int Stud_ID;int Exam_Marks;

};

Page 53: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Structure Pointer : Indirect Component Selection Operator (->)

(cont …)

• We could then define a pointer as follows :Student_Record *sPtr; // Student Pointer - uses no

memory !

• And, then allocate memory for the structure object :

sPtr = new Student_Record; // Allocate memory. if (sPtr == 0) // Was the memory allocated successfully ?{

cerr << "\n*** Out of Memory!\n"; // No !exit(-1); // Exit the program.

}

Page 54: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Structure Pointer : Indirect Component Selection Operator (->)

(cont …)• We could then access the fields in the structure for this object using a mixture of pointer dereferencing and dot notation :cout << "\nEnter a Student ID : ";cin >> (*sPtr).Stud_ID;cout << "\nYou entered : " << (*sPtr).Stud_ID;

• This can look a bit messy / confusing.• Arrow to the rescue !!

cout << "\nEnter a Student ID : ";cin >> sPtr->Stud_ID;cout << "\nYou entered : " << sPtr->Stud_ID;

Page 55: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Structure Pointer : Indirect Component Selection Operator (->)

(cont …)• As you can see, the arrow makes the code nicer to look at.

• At the end, we need to unallocate the memory we had previously reserved :delete sPtr;

Page 56: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Arrays and the New and Delete operations – Pointer to an Array

• In practice the new operation is mostly used to dynamically allocate arrays. e.g. arrays of structures.

• Arrays that are declared using the new operation are no longer constrained to a fixed size that is set when the program is compiled.

• Instead, the array size can be set at run-time, and the only real limits for the size of the array is the amount of free memory on your computer.

• Arrays that are allocated at run-time are said to be dynamic arrays.

• There are two main strategies that we will look at for the allocation of arrays dynamically. Each method has its own advantages and disadvantages.

Page 57: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #1 : Prompt the user to enter the size of the array, and then allocate all in one new

operation.int NumEntries; // The size of our dynamic array.float *fPtr; // Pointer to our dynamic arrayint count = 0;

  cout << "How many values do you require : ";cin >> NumEntries;

 fPtr = new float [NumEntries]; // Allocated memory for our entire array.

 if (fPtr == 0) // Was the memory allocated successfully ?{

cerr << "\n*** Out of Memory!\n"; // No ?exit(-1); // Exit the program.

}

Page 58: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #1 : Prompt the user to enter the size of the array, and then allocate all in one new

operation. (cont …)for (count = 0; count < NumEntries; count++){

cout << "\nEnter value [" << (count+1) << "] : ";cin >> fPtr [count]; // Store value in array.

cout << "\nYou entered these values :" << endl;for (count = 0; count < NumEntries; count++){

cout << "\nValue [" << (count+1) << "] = "<< fPtr [count]; // Display the array

element.}

 delete [] fPtr; // Unallocate / Reclaim ALL memory reserved for the array.fPtr = 0; // Set pointer to zero - for safety !

}

Page 59: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #1 : Prompt the user to enter the size of the array, and then allocate all in one new

operation. (cont …)• The advantages of this method are :– We can allocate memory in one big block – which

makes our code simple.– The size of the dynamic array is only limited by the

amount of free memory in our computer.– We don't need to use any pointer dereferencing to

access the data at each row / element – because we have a pointer to an array - we can just use stock standard array notation once the array is allocated.

• The disadvantages of this method are :– Once the memory has been allocated, the array

size cannot be changed. So, while or after entering array data, for example, the user cannot decide to enter 20 more values than they originally requested.

Page 60: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #2 : Use a static array of pointers.

• For this method we will declare a static array of pointers – which contains room for more elements than we will ever need – and then we can allocate memory for each row of the array as we go.

• This enables the user to keep entering data for as long as they like (as long as they don't exceed the array of pointers size).

Page 61: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #2 : Use a static array of pointers.

(cont …)const MAX_SIZE = 200; // The maximum size of our array.

int NumEntries; // The actual size of our dynamic array.

float *fPtr [MAX_SIZE]; // Static array of pointers.

int count = 0;

char User_Input = 'Y';

 

while ((count < MAX_SIZE) && (User_Input == 'Y'))

{

fPtr [count] = new float;

// Allocated memory for the current array row.

  if (fPtr [count] == 0)

// Was the memory allocated successfully for this row ?

{

cerr << "\n*** Out of Memory!\n";

exit(-1); // Exit the program.

}

Page 62: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #2 : Use a static array of pointers. (cont …)

cout << "\nEnter value [" << (count+1) << "] : "; 

cin >> *fPtr [count]; // Store value in array. 

cout << "Enter more data (Y/N) ?";cin >> User_Input;cin.ignore (80, '\n');

 if ((User_Input == 'y') || (User_Input == 'Y')){

User_Input = 'Y'; // Convert to uppercase.count++;

}} // while loop

NumEntries = count;

Page 63: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #2 : Use a static array of pointers. (cont …)

cout << "\nYou entered these values :" << endl;for (count = 0; count <= NumEntries; count++){

cout << "\nValue [" << (count+1) << "] = "<< *fPtr [count]; // Display the array

element.}

 // For each new operation, we need a corresponding delete operation.for (count = 0; count <= NumEntries; count++){

delete fPtr [count]; // Unallocate memory reserved for this array row.

fPtr [count] = 0; // Set pointer for this row to zero - for safety !}

Page 64: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Strategy #2 : Use a static array of pointers. (cont …)

• The advantages of this method are :– The user can keep entering data until they have entered

enough – as long as the maximum size of our array of pointers is not exceeded.

– Once the user has finished entering data, we can (later on) allow the user to then append more data onto the end of what they have already entered – as long as the maximum size of our array of pointers is not exceeded.

• The disadvantages of this method are :– We must use a new and delete operations to allocate

and deallocate the memory for each row / element of our array – which makes our code more complex.

– We need to use pointer dereferencing to access the data at each row / element – because we have an array of pointers instead of a pointer to an array - which is not really a big deal, but we do have to remember to dereference !

Page 65: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

The void pointer type and Type Casting

• On some occasions you may decide that you require a void pointer type. Void pointers are just like void functions – they have no type.

• Be very careful if you use a void pointer as it can lead to problems, and it can be a dangerous programming practice.

• In fact, C++ is so worried when you use a void pointer, that it makes you type cast it for many operations.

Page 66: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

The void pointer type and Type Casting (cont …)

int number_1 = 10; // Declare and initialise two integers.int number_2 = 20;void *Ptr = NULL; // Declare a void pointer - has NO type !

 Ptr = &number_1; // Assign our Void Pointer to the address of number_1

 // Display the value pointed to by our Void Pointercout << "\nVoid Pointer Dereference = ";cout << *Ptr; // ERROR: dereferencing a void pointer ! We must typecast !cout << endl;

 // Assign the value pointed to by Ptr to number_2number_2 = *Ptr; // ERROR: dereferencing a void pointer ! We must typecast !

 cout << "\nNumber 1 = " << number_1 << ", Number 2 = " << number_2 << endl;

Page 67: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

The void pointer type and Type Casting (cont …)

int number_1 = 10; // Declare and initialise two integers.int number_2 = 20;void *Ptr = NULL; // Declare a void pointer - has NO type !

 Ptr = &number_1; // Assign our Void Pointer to the address of number_1

 // Display the value pointed to by our Void Pointercout << "\nVoid Pointer Dereference = ";cout << *(int*)Ptr; // The first * is the dereference.

// (int *) is the cast or type casting.cout << endl;

 // Assign the value pointed to by Ptr to number_2number_2 = *(int *)Ptr; // The first * is the dereference.

// (int *) is the cast or type casting. 

cout << "\nNumber 1 = " << number_1 << ", Number 2 = " << number_2 << endl;

Page 68: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Array of Pointers : 2D Arrays• Quite a useful structure to have is an

array of pointers with a fixed number of rows with variable size / length columns.

• Such an array would be a two dimensional (2D) array, and would provide efficient storage for an array of variable length strings.

• Such an array could be declared as follows :char *Ptr_Words[5];

Page 69: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Array of Pointers : 2D Arrays (cont …)

const int MAX_STRINGS = 5;const int MAX_STRING_SIZE = 81;char *Ptr_Words [MAX_STRINGS]; // Base address of 2D arraychar answer [MAX_STRING_SIZE];int row = 0;

 cout << "\nPlease enter 5 strings of any length up to 80 characters :" << endl;

 

Page 70: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Array of Pointers : 2D Arrays (cont …)

for (row = 0; row < MAX_STRINGS; row++){

cout << "\nEnter string " << (row + 1) << " ";cin.getline (answer, MAX_STRING_SIZE);

 // Allocate memory for this string - add 1 for the null terminator.Ptr_Words [row] = new char [strlen (answer) + 1];

 if (Ptr_Words [row] == 0) // Was the memory allocated

successfully ?{

cerr << "\n*** Out of Memory!\n"; // No !exit(-1); // Exit the program.

// Store String in array.strcpy (Ptr_Words [row], answer);

}

Page 71: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Array of Pointers : 2D Arrays (cont …)

// Display Strings entered by the user.for (row = 0; row < MAX_STRINGS; row++){

cout << "\nString Num = " << (row + 1)<< ", Length = " << strlen (Ptr_Words [row])<< ", String = " << Ptr_Words [row]<< endl;

// Clean-up deallocate memory.for (row = 0; row < MAX_STRINGS; row++){

delete [] Ptr_Words [row]; // Unallocate memory reserved for string.

Ptr_Words [row] = 0; // For safety !}

Page 72: 310201 Fundamental Programming Pointers and Dynamic Memory

                                           

Review of this week's material

• Pointers will seem difficult at first !• Your understanding of pointers is

crucial if you plan to undertake further studies in C++, Java, etc.

• As with everything we have covered this term, the only way to learn is hands on experience : write lots of programs using pointers until you become comfortable with them.