460 likes | 609 Views
Engineering Problem Solving With C++ An Object Based Approach. Chapter 9 Pointers and Creating Data Structures. Pointer Basics. A pointer is a variable that holds the memory address of another object
E N D
Engineering Problem Solving With C++An Object Based Approach Chapter 9 Pointers and Creating Data Structures
Pointer Basics • A pointer is a variable that holds the memory address of another object • If a variable p contains the address of another variable q, then p is said to point to q • If q is a variable at location 100 in memory, then p would have the value 100 (q’s address)
Address Of Operator • The & operator is called the addressof operator. • The operator & in front of any variable produces the address of that variable. • Example: int x=75; cout << "x is " << x; cout << "\nthe addres of x is " << &x; 0x7fff8164 x 75 x is 75 the address of x is 0x7fff8164
How to declare a pointer variable • pointer variables are declared using the indirection operator*, more commonly called the dereferencing operator. • general form - • type *variable_name, *variable_name; • type* variable_name; • when declaring more than one pointer variable, the * must precede each variable.
Example int *iPtr; double* dPtr; • the variable iPtr is declared to be of type pointer to int • the variable dPtr is declared to be of type pointer to double • neither variable in this example has been initialized • declaring a pointer creates a variable capable of holding an address
Example int *iPtr, i=6;char* s, str = "example";double *dPtr, d=1.25; iPtr s dPtr i str d 6 "example" 1.25
NULL pointer • there is a literal value that can be assigned to any pointer • the literal value is NULL or 0 • in this context it is known as the nulladdressand does not point to anything which can be referenced. • trying to dereference the null address, results in a terminal error
Example int *iPtr=0; char *s=NULL; //predefined constant in iostream.h double *dPtr=NULL; NULL iPtr s dPtr NULL NULL
x xp ip Assigning values to a pointer • the assignment operator (=) is defined for pointers • the right operand of the assignment operator can be any expression that evaluates to the same type as the left Example: int x, *xp, *ip; xp = &x; ip = xp;
The Base Type • In the declaration int *p; // the base type of p is int double *q; // the base type of q is double • Base type determines the size of an object to which the pointer is assumed to be pointing • The size of p and q are the same ( 4 bytes**), but p points to 4 bytes** and q points to 8 bytes** **compiler dependent
Base Type continued • A pointers base type determines how the contents of the memory location pointed to by the pointer will be interpreted • The declaration: int *p; declares p to be a pointer to int. What ever p points to will be interpreted as an int, whether or not it actually is an int • Base type also affects pointer arithmetic
Pointer Arithmetic • Four arithmetic operations are supported • +, -, ++, -- • only integers may be used in these operations • Arithmetic is performed relative to the base type • When applied to pointers, ++ means increment pointer to point to nextobject Example: p++; • if p is defined as int *p, p will be incremented by 4 • if p is defined as double *p, p will be incremented by 8
Example int *p; cout << "size of char is " << sizeof(char) << endl; cout << "size of int is " << sizeof(int) << endl; cout << "size of double is " << sizeof(double) << endl; cout << "size of float is " << sizeof(float) << endl; cout << "the size of p is " << sizeof(p) << endl; Output: size of char is 1 size of int is 4 size of double is 8 size of float is 4 the size of p is 4
Practice! (Use the information from previous slide) int q=6; int *iPtr = &q; cout << "iPtr is " << iPtr << endl; cout << "*iPtr is " << *iPtr << endl; cout << "++*iPtr, is " << ++*iPtr << endl; cout << "q is " << q << endl; cout << "iPtr is " << iPtr << endl; cout << "*iPtr++ is " << *iPtr++ << endl; cout << "iPtr is " << iPtr << endl; cout << "q is " << q << endl; If the first line of output is iPtr is 0x7fff2f14 what is the remaining output?
Result of Practice iPtr is 0x7fff2f14 *iPtr is 6 ++*iPtr is 7 q is 7 iPtr is 0x7fff2f14 *iPtr++ is 7 iPtr is 0x7fff2f18 q is 7
Comparing Pointers • You may compare pointers using relational operators • Common comparisons are: • check for null pointer (p == NULL) • Note: since NULL evaluates as false, and any other pointer evaluates as true, checking for a null pointer can be done as (!p) • check if two pointers are pointing to the same object (p == q) • Note: (*p == *q) means they are pointing to equivalent, but not necessarily the same data.
Pointers and Arrays • The name of an array is the address of the first element (i.e. a pointer to the first element) • Arrays and pointers may often be used interchangeably Example int num[4] = {1,2,3,4}, *p; p = num; //same as p = &num[0]; cout << *p<<endl; p++; cout << *p; 1 2
More Pointers and Arrays • You can also index a pointer using array notation Example: char myString[] = "This is a string"; char *str; str = myString; for(int i =0; str[i]; i++) //look for null cout << str[i]; What does this segment print? This is a string
Arrays and Pointers • The name of an array is a pointer to the first element. However, the array name is not a pointer variable. It is a constantpointer that always points to the first element of the array and its value can not be changed. • Also when an array is declared, space for all elements in the array is allocated, however when a pointer variable is declared only space sufficient to hold an address is allocated
0xfff4c252 myString T h i s i s a s t r i n g \0 strPtr 0xfff4c252 Practice! What does this print? char myString[ ] = "This is a string"; char *strPtr; strPtr = myString; cout << *myString << endl; cout<<myString << endl; cout << *(myString + 1) << endl; strPtr++; cout << *++strPtr << endl; myString++; //not legal T This is a string h i
Arrays of Pointers • You may define arrays of pointers like any other data type in C++ int num=8; //declare an array of 10 pointers to int int *iPtrs[10]; //first element is assigned a value iPtrs[0] = # //output the value of num cout << *iPtrs[0];
Arrays of Type char pointers • char *words[ ] ; //array of pointers to char int main(int argc, char *argv[ ]) { for(int I =1; I<argc; I++) cout << argv[I] << endl; //ouput Ith string } output all arguments, not the command a.out filename1 filename2 filename3 (argc is 4)
Passing Pointers As Parameters • Pointers may be passed either "by value" or "by reference". • In either case, the pointer can be used to modify the object to which it is pointing. • Only when passed by reference can the pointer argument be modified.
Common Pointer Problems • Using uninitialized pointers int *iPtr; *iPtr = 100; iPtr has not been initialized. The value 100 will be assigned to some memory location. Which one determines the error. • Failing to reset a pointer after altering it’s value • Incorrect/unintended syntax
Practice! • #include <iostream> • using namespace std; • int main() • { char *aString = "What happens here?"; • int len=0; • while(*aString++ != '\0') • len++; • cout << len << ": " << aString; • return 0; • } • Does this compile? If not, why? • If it does, what is the output? Why? Yes 18:
Stack Heap Global data Program code Dynamic Allocation Using new and delete • Storage for data is allocated as needed from the free memory area known as the heap (or the freestore). • Run-time stack • Local variables • Formal parameters • Managed by the compiler • Heap • Dynamic storage • Managed by storage allocator
Dynamic Memory Allocation • Dynamically allocated memory is determined at runtime • It allows a program to create as many or as few variables as required, offering greater flexibility • Dynamic allocation is often used to support data structures such as stacks, queues, linked lists and binary trees. • Dynamic memory is finite • Dynamically allocated memory may be freed during execution
Operator new • Replaces malloc() used in C • Creates a new dynamic variable of the specified type • Returns a pointer to the new variable • If allocation fails, new terminates the program (or returns NULL on older compilers)
Example int *iPtr; iPtr = new int; // 4 bytes are allocated // iPtr points to new integer // variable double *dPtr; dPtr = new double[20]; // dPtr points to the first // double in anarray // of 20 doubles (160 bytes // allocated)
new - continued • If your compiler returns NULL when new fails, it is a good idea to check after each request. int *p; p = new int; //if assertion is false, program ends and error //message is issued assert(p != NULL); • assert is defined in cassert
Initializing Dynamically Allocated Memory • To initialize a dynamically allocated variable, specify the initial value inside parentheses after the type name. • Example: int *ptr; ptr = new int(100); //new variable pointed to //by ptr has a value of 100
iPtr jPtr ? ? ? ? ? ? dptr Practice: int main() { int *iPtr, *jPtr, i; iPtr = new int; jPtr = new int(3); double *dPtr; dPtr = new double[6]; *iPtr = 7; //SKETCH MEMORY cout << *iPtr << ',' << *jPtr << endl; for(i=0; i<6; i++) dPtr[i] = 5; for(i=0; i<6; i++) cout << (*dPtr)++ << ' '; cout << endl; for(i=0; i<6; i++) cout << dPtr[i] << ' '; return 0; //OUTPUT? } 7 3 OUTPUT 7 , 3 5 6 7 8 9 10 11 5 5 5 5 5
constModifier with pointers const int *cPtr, *cPtr2; int n=3; cPtr = new int (10); cPtr2 = &n; //can not modify what is pointed to by //cPtr or cPtr2
Operatordelete • Replaces free() function used in C • The delete operator frees memory produced by new • Using delete to attempt to free any other type of address will produce problems • While delete uses a pointer variable, it does not destroy the pointer variable, it only frees the storage to which the variable is pointing.
100 delete Example int *ptr; ptr = new int (100); cout << *ptr; //see if it worked delete ptr; //free the memory value of ptr is now undefined
Example of dynamically allocated arrays double *dptr; const int size = 10; dptr = new double[size]; //allocate 10 doubles for(int I=0; I<size; I++) //read values into array cin >> dptr[I]; fun1(dptr, size); // pass array to fun1 delete [] dptr; //free all 10 elements prototype for fun1: void fun1(double*, int);
Example using delete int *iPtr, *jPtr; iPtr = new int(2); jPtr = new int(3); cout << *iPtr << ',' << *jPtr << endl; delete iPtr; delete jPtr; cout << *iPtr << ',' << *jPtr << endl; int *dPtr; dPtr = new int(5); cout << iPtr << ',' << jPtr << endl; cout << *iPtr << ',' << *jPtr << endl; cout << dPtr << endl; What would you expect from this code?
Data Structures • Dynamic memory allocation is used to implement data structures such as • stacks • queues • linked lists
Stacks • Last-In-First_Out (LIFO) • Many processes exhibit this behavior • control when computing function calls • compiler design (language parsing) • cafeteria tray stacks
Implementing Stacks • Stacks can be implemented using an array • concern with exceeding bounds of the array • Linked structures are a more natural way stack 5 7 7 NULL • Allocate newmemory each time a value is added to the stack
Stack operations • Create Stack • Stack points to NULL • Empty • returns true if stack is empty • Push • Insert a value into the head of the list (top of the stack) • Top • Return the value of the head (top) of the stack • Pop • Remove element from top of stack
Example • Create • Push 2 • Push 4 • Pop • Top • Stack Stack 2 Stack 4 2 Stack 2
Queues • First-In-First_Out (FIFO) • Many processes exhibit queuing behavior • Waiting lines of people • Job requests • Requests for computer resources
Implementing Queues • Queues require both a head (front) and a tail (rear) pointer • Values are added to the tail • Values are retrieved from the head 5 7 8 head tail
Queue operations • Create queue • Creates an empty queue by setting head and rear to NULL • Empty • Returns true if the queue is empty, and false otherwise • InsertTail • Inserts a new item to the rear of the queue • DeleteHead • Deletes the node at the front of the queue
Example • Create • InsertTail 2 • InsertTail 4 • DeleteHead • Head Head 2 2 Head Tail 4 Tail Head Tail 4