570 likes | 817 Views
Data Structures. Pointers - Dynamic Arrays – Vector STL. x. 25. ptr. 0x7e00. Address of x: 0x7e00. Pointer Illustration. Pointer variables, which are often just called pointers, are designed to hold memory addresses.
E N D
Data Structures Pointers - Dynamic Arrays – Vector STL
x 25 ptr 0x7e00 Address of x: 0x7e00 Pointer Illustration • Pointer variables, which are often just called pointers, are designed to hold memory addresses. • With pointer variables you can indirectly manipulate data stored in other variables.
Pointers are useful for the following: • Working with memory locations that regular variables don’t give you access to • Working with strings and arrays • Creating new variables in memory while the program is running • Creating arbitrarily-sized lists of values in memory
Memory Terminology Addresses 00110 01010 01110 10010 10110 15 x
Memory Terminology (cont.) Addresses Variable name 00110 01010 01110 10010 10110 15 x
Memory Terminology (cont.) Addresses 00110 01010 01110 10010 10110 15 x A variable (which is a location)
Memory Terminology (cont.) Addresses 00110 01010 01110 10010 10110 15 x Value of the variable
Memory Terminology (cont.) Addresses 00110 01010 01110 10010 10110 15 x Address of the variable
First look at pointers • When a variable is declared, space in memory is reserved for it. • A pointer is a variable used to store an address • A pointer represents the memory address of a variable, NOT its value. • The declaration of a pointer must have a data type for the address the pointer will hold: int *ptr; char *chptr;
type *ptr; int *intPtr; char *charPtr; Declaring Pointer Variables • Declare a pointer by stating the type followed by the variable name, but with a "*" added immediately before the name. • The pointer ptr is a variable whose value is the address of a data item of the designated type.
First look at pointers • Two fundamental operations: assignment and dereferencing • Assignment is used to set a pointer variable’s value to a memory address • &(“address of” operator) gives the address of a variable • Dereferencing returns the value stored at the location represented by the pointer’s value • *(dereference operator) evaluates to the value of the memory referred to by the pointer
Address-of operator • An address can be assigned to a pointer using the address-of operator &: int *ptr; int x; ptr = &x;
Result ptr x Addresses 00110 01010 01110 10010 10110 x ptr 01010
Assigning Values to Pointers • &m is the address of the integer in memory. The assignment statement • sets intPtr to point at an actual data item. • The Figure illustrates the status of the two variables from the declaration statement and the resulting status after the assignment of a value to intPtr. int m = 50, *intPtr; intPtr = &m;
Assigning Values to Pointers int x = 10; int *p; p = &x; p gets the address of x in memory. p 10 x
Assigning Values to Pointers int x = 50, y = 100, *px = &x, *py = &y;
Accessing Data with Pointers • The operator * is called the deference operator. • It combines with pointer to allow access to the contents of the variable referenced by the pointer. int x = 50, y = 100, *px = &x, *py = &y; *px= *py +2; //assign to x the value y + 2 =102 *py *=2; //double value of y to 200 (*px)++; //increase x from 102 to 103
Accessing Data with Pointers int x = 10; int *p; p = &x; *p = 20; *p is the value at the address p. p 20 x
Pointers Declares a pointer to an integer int x = 10; int *p = NULL; p = &x; *p = 20; & is address operator gets address of x *dereference operator gets value at p
Use of address-of (&) Operator – Program // This program uses the address-ofoperator ‘&’ to determine a variable’s // address and the sizeof operator to determine its size. #include <iostream> using namespace std; int main() { intX = 25; cout << "The address of X is " << &X << endl; cout << "The size of X is " << sizeof(X) << " bytes\n"; cout << "The value in X is " << X << endl; cin >> X; return 0; } // main The address of X is 002DF88C The size of X is 4 bytes The value in X is 25
Pointer Variables – Program // This program stores the address of a variable in a pointer. #include <iostream> using namespace std; int main() { int X = 25; int * a; //pointer of type integer a = &X; //gets address of variable X cout << "The address of X is " << a << endl; cout << "The value in X is " << X << endl; cin >> X; return 0; } // main The address of X is 0037FD40 The value in X is 25
Dereference (*) Operator – Program // This program demonstrates the use of the dereference operator (*). #include <iostream> using namespace std; int main(){ int X = 25; int * a; a = &X; //store the address of X in a cout << "The address of X is " << a << endl; cout << "Here is the value X, printed twice:\n"; cout << X << " " << *a << endl; *a = 100; // Note indirection is a unary operator cout << "Once again, here is the value in X:\n"; cout << X << " " << *a << endl; cin >> X; return 0; } // main The address of X is 0035F954 Here is the value X, printed twice: 25 25 Once again, here is the value in X: 100 100
Exercise • Demonstrate knowledge of assignment and dereferencing • Write the code to read in an integer, access it via a pointer, add five to it, and then print it out.
Arrays • Array is a common data structure built into many programming languages. C++ arrays can be single or multidimensional as well as static or dynamic. • A dynamic array is an array whose size is determined when the program is running, not when you write the program. • Dynamic arrays require basic manual memory management • manually create and destroy the array within code and keep track of the allocated memory through pointers. • Failing to destroy an array once a program is done with it can lead to memory leaks, which can effect the overall application and system performance.
Arrays • The address of an array is the same as the address of the first element of the array. • An array’s name (without using an index [ ]) contains the address of the array. • The address of the array can be assigned to a pointer by assigning the array’s name to the pointer. • An array name is not a pointer because the address in it cannot be changed (the address in a pointer can be changed).
The Relationship Between Arrays and Pointers • An Array name is a constant pointer to the first element in an array. It holds an address. intvals[] = {4, 7, 11}; cout << vals; // displays 0x4a00 cout << vals[0]; // displays 4 starting address of vals:0x4a00
The Relationship Between Arrays and Pointers • an Array name can be used as a pointer constant: intvals[] = {4, 7, 11}; cout << *vals; // displays 4 • A Pointer can be used as an array name: int*valPtr = vals; cout << valPtr[1]; //displays 7 cout << *(valPtr+1); //displays 7 cout << valPtr; //displays address of vals
Array Access • Array elements can be accessed in many ways: • Use of [ ] subscript and * offset notation
Array Access • Conversion: • vals[i]is equivalent to*(vals + i) • No bounds checking performed on array access, whether using array name or a pointer
Pointers and Arrays – Program #include <iostream> using namespace std; int main() { int Numbers[5]; int wasted; cout << "Enter five numbers: "; for ( int Count = 0; Count < 5; Count++ ) cin >> *(Numbers + Count); cout<< "Here are the numbers you entered:\n"; for ( int Count = 0; Count < 5; Count++ ) cout << *(Numbers + Count)<< " "; cout << endl; cin >> wasted; return 0; } // main Enter five numbers: 45 26 5 9 479 Here are the numbers you entered: 45 26 5 9 479
Pointer Arithmetic – Program #include <iostream> using namespace std; int main(){ int Set[8] = {5, 10, 15, 20, 25, 30, 35, 40}; int *Nums, Index; int wasted; Nums= Set; cout << "The numbers in Set are:\n"; for ( Index = 0; Index < 8; Index++ ) { cout << *Nums << " "; Nums++; } // for cout << "\nThe numbers in Set backwards are:\n"; for ( Index = 0; Index < 8; Index++ ) { Nums--; cout << *Nums << " "; } // for cin >> wasted; return 0; } // main The numbers in Set are: 5 10 15 20 25 30 35 40 The numbers in Set backwards are: 40 35 30 25 20 15 10 5
The Heap • The heap is a special part of RAM memory reserved for program usage. • When a program uses memory from the heap, the used heap memory is called dynamically-allocated memory. • The only way to dynamically allocate memory (use memory in the heap) is by using the new operator.
Allocating memory usingnew Operator • The new operation produces the address of an unused chunk of heap memory large enough to hold a data type (dynamically allocated) • In order to be useful, the address must be assigned to a pointer, so that the dynamically allocated memory can be accessed through the pointer: int *ptr; ptr = new int; *ptr = 5;
Dynamically-allocated memory • Has no name associated with it (other locations have variable names associated with them) • Can only be accessed by using a pointer • The compiler does not need to know the size (in bytes) of the allocation at compile time • The compiler doesneed to know the size (in bytes) of any declared variables or arrays at compile time
Creating Dynamic Arrays • Normal arrays require that the programmer determine the size of the array when the program is written • What if the programmer estimates too large? • Memory is wasted • What if the programmer estimates too small? • The program may not work in some situations • Dynamic arrays can be created with just the right size while the program is running
Dynamic Array Allocation • To avoid wasting memory, array allocation or deallocation can take place at run time. • To allocate memory, we need to use the new operator Reserves the number of bytes requested by the declaration. Returns the address of the first reserved location or NULL if sufficient memory is not available. • To deallocate memory (which has previously been allocated using the new operator) we need to use the delete operator. Releases a block of bytes previously reserved. The address of the first reserved location is passed as an argument to the function.
Using new with arrays • Since an array name is a constant pointer, an array can dynamically allocate memory from the heap int x = 10; int *nums1 = new int[10]; // ok int *nums2 = new int[x]; // ok • Initializes an array of 10 integers on the heap.
Using new with multidimensional arrays int x = 3, y = 4; int **nums3 = new int[x][4];// ok int **nums4 = new int[x][y];// BAD! • Initializes a multidimensional array • Only the first dimension can be a variable. The rest must be constants. • Use single dimension arrays to fake multidimensional ones
Deallocating memory using delete // allocate memory ptr = new int; ... // free the memory delete ptr; For every call to new, there must be exactly one call to delete. • Use the new operator to dynamically allocate memory. • Use delete to dynamically deallocate memory.
Using delete on arrays // allocate memory int* nums1 = new int[10]; int* nums3 = new int[x][4][5]; ... // free the memory delete [] nums1; delete [] nums3; • Have to use delete[].
The delete Operator (cont.) • When the delete operator is being used to free a variable pointed to by ptr: delete ptr; • When the delete operator is being used to free an array pointed to by ptr: delete [ ] ptr; • If you omit [ ] (common mistake), no compiler error will be given; however, only the first element of the array will be freed
What Happens at the End of This Function? 1 void foo( ) 2 { 3 intnumElements; 4 cout << 5 “How many elements would you like the array to have? “; 6 cin >> numElements; 7 float *ptrArr = new float [ numElements ]; 8 9 // the array is processed here 10 // output to the user is provided here 11 }
Memory Leak • All local variables and the values they contain are destroyed (numElements and ptrArr) • The address of the dynamic array is lost • BUT…the dynamic array is not destroyed • The dynamic array can no longer be used, but the new operator will consider it as used heap memory (and cannot reuse it for something else). • This is called memory leak. • Memory leak is not permanent – it will end when the program stops.
Memory Leak (cont.) • Memory leak can easily be prevented during execution of a program. • A program that continually leaks memory may run out of heap memory to use. • Therefore, it is poor programming practice to allow memory leak to occur.
The delete Operator 1 void foo( ) 2 { 3 intnumElements; 4 cout << 5 “How many elements would you like the array to have? “; 6 cin >> numElements; 7 float *ptrArr = new float [ numElements ]; 8 9 // the array is processed here 10 // output to the user is provided here 11 12 delete [ ] ptrArr; 13 } Prevents memory leak – it frees the dynamic array so this memory can be reused by the new operator later on