440 likes | 518 Views
C++ Pointers and Arrays. CSCD 326. Variable Attributes. Attributes of a “variable”: Contents - the value stored in the memory location(s) used for the variable Address - each byte of memory has a unique address which allows the CPU to access that memory location
E N D
C++ Pointers and Arrays CSCD 326
Variable Attributes • Attributes of a “variable”: • Contents - the value stored in the memory location(s) used for the variable • Address - each byte of memory has a unique address which allows the CPU to access that memory location • Access to a named variable’s attributes: • variable name - a reference to the value of the variable • e.g. x = x + 3 • &variable name - a reference to the address at which the variable is stored • e.g. &x CSCD 326
Pointers and Indirect References • Pointers are variables used to store the address of another memory location • Pointers provide indirect access to a value stored in memory • Using the address stored in a pointer to access a value stored in that address is called dereferencing the pointer Addresses Contents 10A0 Pointer 2000 2000 5 CSCD 326
Address 1000 1004 1008 C++ Pointer syntax • Declaration of a pointer object (variable) int *Ptr; • this declares an object or variable called Ptr which can contain the address of an integer object • Pointer Assignment int X = 5; int Y = 7; Ptr = &Y; //&Y is the address of Y Name Contents Ptr 1008 7 X 5 Ptr Y Y 7 CSCD 326
Address 1000 1004 1008 Dereferencing Operator • Allows access to the value of the data whose address is contained in a pointer for use in an expression or assignment • *Ptr evaluates to 7 • *Ptr = 15; -- assigns value 15 to the integer whose address is contained in Ptr • * is the opposite of & so: *(&X) is the same as X Name Contents Ptr 1008 15 X 5 Ptr Y Y 15 CSCD 326
#include <iostream.h> #include <stdlib.h> void main() { int *ptr, i = 15; // assignment of addresses to a pointer variable ptr = NULL; ptr = (int *)0xfffe; ptr = &i; cout << "address of i: " << ptr << "\n"; cout << "contents of i: " << *ptr << "\n"; } Pointer Example CSCD 326
Pointer Example Output address of i: 0x0012FF78 contents of i: 15 Press any key to continue CSCD 326
Pointer expressions #include <stdlib.h> #include <iostream.h> void main() { int i = 3, j = 5, k; int *p = &i, *q = &j, *r; *(r = &k) = *p * *q; cout << "r: " << *r; } Output: r: 15 CSCD 326
Pointer expressions memory i 3 j 5 k p &i q &j r CSCD 326
SmallArray[0] SmallArray[1] SmallArray[2] SmallArray[3] SmallArray[4] Arrays and Pointers int SmallArray[] = {1,3,5,7,9}; int *Iptr; Iptr = SmallArray; Name Address 1000 1 SmallArray 1004 3 5 1000 1008 7 100C 9 1010 Iptr 1014 1000 CSCD 326
SmallArray[0] SmallArray[1] SmallArray[2] SmallArray[3] SmallArray[4] Array address calculations • To determine the address of SmallArray[I]: • compiler calculates - SmallArray + (I * 4) • or 1000 + (I * 4) Name Address 1000 1 SmallArray 1004 3 5 1000 1008 7 100C 9 1010 Iptr 1014 1000 CSCD 326
Pointer Arithmetic • Pointer arithmetic can be used in the same way as array notation to access array members • Recall from previous example: • Iptr = SmallArray; • the members of SmallArray can now be accessed as: • *(Iptr +1) *(Iptr +2)etc. • or as*(SmallArray + 1) *(SmallArray + 2) • Since both Iptr and SmallArray are pointers, these expressions are pointer arithmetic • *(Iptr + I) is evaluated as: • Iptr + (I * sizeof(*Iptr)) or Iptr + (I * 4) in this case • So - *(SmallArray + I) is the same as: SmallArray[I] CSCD 326
Category Operator Associativity Overloadable Scoping ::(unary) ::(class) L to R No Postfix () [] -> . ++ -- L to R Yes, except . Prefix sizeof * & ! ~ + - ++ -- new delete R to L Yes, except sizeof Pointer Operators and precedence • Shown below is the top of the C++ precedence chart: • consider the following expressions: • int X[5], *Ptr = X; • *Ptr++ ++*Ptr ++X[0] Ptr++[0] • ++X[2] CSCD 326
Strings • C++ has its own string type and can be accessed via the standard template library (STL). • More specifically, you #include <string> and follow it with the statement: using namespace std;. • The using namespace std; further requires that all other C++ header files are included without a .h. • Furthermore, old C style libraries are included by preceding the library name with a c (once again the .h is left off) • C type strings are still supported and we will use them- you may use your own user-defined string classes in programs CSCD 326
C type Strings • C strings are arrays of characters in which the end of the string is indicated by a char containing 0 (character constant ‘\0’) • the string array must be large enough to accommodate the extra terminal character • C strings are of type char * or const char * char astr[7]; int i; OR astr[0] = ‘s’; *(astr) = ‘s’; astr[1] = ‘t’; *(astr + 1) = ‘t’; astr[2] = ‘r’; *(astr + 2) = ‘r’; astr[3] = ‘i’; *(astr + 3) = ‘i’; astr[4] = ‘n’; *(astr + 4) = ‘n’; astr[5] = ‘g’; *(astr + 5) = ‘g’; astr[6] = ‘\0’; *(astr + 6) = ‘\0’ CSCD 326
C String Functions #include <string.h> char * strcpy(char *, const char *); char * strcat(char *, const char *); int strcmp(const char *, const char *); size_t strlen(const char *); • strcpy- copies characters from its second parameter to its first - returns the address of the string copied to • strcat - adds characters in second parameter to the end of the first CSCD 326
C String Functions (cont) • strcmp- compares characters from second argument to those from first - return value indicates either equality or which string is larger • return value: • <0 - string1(first arg) less than string2 • 0 - the strings are identical • > 0 - string1 is greater than string2 • strlen - counts characters in its argument - up to but NOT including the terminal 0 and returns this count CSCD 326
String Constants • Specified with quotes -- “string” • Placed into memory allocated by the compiler with the nul terminator added • thus “string” occupies 7 bytes of memory • Uses of string constants: • can be used anywhere both a string and a constant can - e.g. as the second (but not first) parameter to strcpy • as array initializers: char str[10] = “string”; here characters are copied from the constant to the array • assignment to pointers: char *mystr = “string”; here the address of the memory location of the constant is assigned to mystr CSCD 326
Pointer Hopping #include <stdio.h> void strcpy1(char s[],char t[]); void strcpy2(char *s,char *t); void strcpy3(char *s,char *t); void strcpy4(char *s,char *t); void main(void) { char s1[50], *s2; s2 = "this is a literal string"; printf("s1: %s\ns2: %s\n",s1,s2); //cout << “s1:” << s1 << “\ns2: “ << s2 << “\n”; strcpy1(s1,s2); printf("s1: %s\ns2: %s\n",s1,s2); } CSCD 326
Pointer Hopping (2) void strcpy1(char s[],char t[]) { int i; i = 0; while((s[i] = t[i]) != '\0') { s++; t++; } } void strcpy2(char *s, char *t) { while((*s = *t) != '\0') { s++; t++; } } CSCD 326
Pointer Hopping (3) void strcpy3(char *s, char *t) { while((*s++ = *t++) != '\0') ; } void strcpy4(char *s, char *t) { while(*s++ = *t++) ; } CSCD 326
Dynamic Memory Allocation • The new[ ] and delete [] operators can be used to allocate variable sized blocks of memory for classes, structures and arrays while a program is running • static allocation (at the start of a program or function) often requires too much memory to be allocated and wasted • example of dynamic array allocation char *str; str = new char[5]; // allocates 5 bytes Assert(str); strcpy(str, “test”); delete [ ] str; str = NULL; CSCD 326
Memory Leaks • Happen any time memory allocated with new is not returned with delete • Scope related example: void F( int i ) { int A1[10]; int *A2 = new int [10]; … G(A1); G(A2); } • When scope is exited memory from automatic array A1 is freed but not memory pointed by A2 - 10 ints leak - delete [] A2 would fix CSCD 326
Extending Arrays • The new and delete operators can be used to reallocate arrays during program execution to make them larger • the following program reads an infinite number of integers - until 0 is read - and stores them in an extensible array CSCD 326
#include <iostream> #include <cstdlib> using namespace std; // Read an unlimited number of ints. // Return a pointer to the data, and set ItemsRead. int * GetInts( int & ItemsRead ) { int ArraySize = 0; int InputVal; int *Array = 0; // Initialize to NULL pointer ItemsRead = 0; cout << "Enter any number of integers: "; while( cin >> InputVal ) { if( ItemsRead == ArraySize ) { // Array Doubling Code int *Original = Array; Array = new int[ ArraySize * 2 + 1 ]; for( int i = 0; i < ArraySize; i++ ) Array[ i ] = Original[ i ]; delete [ ] Original; // Safe if Original is NULL ArraySize = ArraySize * 2 + 1; } Array[ ItemsRead++ ] = InputVal; } return Array; } CSCD 326
#include <new> //allows us to handle memory exceptions using namespace std; main( ) { int *Array; int NumItems; // The actual code try { Array = GetInts( NumItems ); for( int i = 0; i < NumItems; i++ ) cout << Array[ i ] << '\n'; } catch( bad_alloc exception ) { cerr << "Out of memory!" << endl; exit( 1 ); } return 0; } CSCD 326
Memory Exhaustion • A mechanism is needed to report when dynamically allocated memory (heap) is exhausted • C mechanism - new returns NULL pointer • C++ exception mechanism • VC++ 6.0 – must #include <new>, which allows new to throw a C++ exception of type bad_alloc in the event of an allocation failure • in your code, you can use try/catch exception handling constructs to detect and handle bad_alloc exceptions CSCD 326
Reference Variables (& parameters) • A reference type is a pointer constant which is always dereferenced implicitly • example: int LongVariableName = 0; int & Cnt = LongVariableName; Cnt += 3; • reference variables must be initialized - they are constants • reference variable names are implicitly dereferenced unlike all other pointer types • example of reference types as parameters: CSCD 326
Swap Functions #include <iostream.h> void SwapWrong( int A, int B ); void SwapPtr( int *A, int *B ); void SwapRef( int & A, int & B ); // Simple program to test various Swap routines main( ) { int X = 5; int Y = 7; SwapWrong( X, Y ); cout << "X=" << X << " Y=" << Y << '\n'; SwapPtr( &X, &Y ); cout << "X=" << X << " Y=" << Y << '\n'; SwapRef( X, Y ); cout << "X=" << X << " Y=" << Y << '\n'; return 0; } CSCD 326
// Does not work void SwapWrong( int A, int B ) { int Tmp = A; A = B; B = Tmp; } // C Style -- using pointers void SwapPtr( int *A, int *B ) { int Tmp = *A; *A = *B; *B = Tmp; } // C++ style -- using references void SwapRef( int & A, int & B ) { int Tmp = A; A = B; B = Tmp; } CSCD 326
2D Arrays and Pointers (1) #include <stdio.h> void main(void) { int array[3][4],i,j,val=0; for(i=0;i < 3; i++) for(j=0; j < 4; j++) { array[i][j] = val++; printf("array[%d][%d]: %d\n",i,j,array[i][j]); } printf("array: %x\n",array); printf("array[0]: %x\n",array[0]); printf("array[1]: %x\n",array[1]); printf("*array[1]: %d\n",*array[1]); printf("*array+1: %x\n",*array+1); printf("*array[2]: %d\n",*array[2]); printf("*array+2: %x\n",*array+2); printf("**array+2: %d\n",**array+2); printf("*(*(array+1)+2): %d\n",*(*(array+1)+2)); printf("*(array+1)+2: %x\n",*(array+1)+2); printf("*array[3]: %x\n",*array[3]); } CSCD 326
array[0][0]: 0 array[0][1]: 1 array[0][2]: 2 array[0][3]: 3 array[1][0]: 4 array[1][1]: 5 array[1][2]: 6 array[1][3]: 7 array[2][0]: 8 array[2][1]: 9 array[2][2]: 10 array[2][3]: 11 array: effff804 array[0]: effff804 array[1]: effff814 *array[1]: 4 *array+1: effff808 *array[2]: 8 *array+2: effff80c **array+2: 2 *(*(array+1)+2): 6 *(array+1)+2: effff81c *array[3]: 0 2D Arrays and Pointers (2) CSCD 326
81c 808 804 80c 810 814 830 820 824 828 82c 818 10 4 6 3 1 5 2 0 7 8 9 11 2D Arrays and Pointers (3) array: effff804 array[0]: effff804 array[1]: effff814 *array[1]: 4 *array+1: effff808 *array[2]: 8 *array+2: effff80c **array+2: 2 *(*(array+1)+2): 6 *(array+1)+2: effff81c *array[3]: 0 array -- effff804 (804) each row contains 16 bytes array[0] array[1] array[2] CSCD 326
Pointers and Structures • Structures are an aggregate data type of different types struct Student { char FirstName[40]; char LastName[40]; int StudentNum; double GradePointAvg; } Student S; • declares and allocates an entire structure named S Student *Sptr = &S; • declares, allocates and initializes a pointer Sptr which points at S CSCD 326
Struct member access through pointers • One way to access the members of S through Sptr is: (*Sptr).GradePointAvg • since this is awkward at best, an operator has been provided which both dereferences and provides member selection: Sptr->GradePointAvg • this has exactly the same meaning as the previous expression CSCD 326
Structs as parameters • Call by value prototype: void PrintInfo( Student ThisStudent); • results in a copy being made of the entire actual parameter • Call by reference prototype: void PrintInfo( Student & ThisStudent ); • since only the address of the actual parameter is passed no copy is made • Call by constant reference parameter void PrintInfo( const Student & ThisStudent); • here no copy is made and no changes can be made to the actual parameter CSCD 326
Exogenous vs. Indigenous Data • The student struct as illustrated before contains all indigenous data - All data is contained inside the stuct • Exogenous data - data allocated outside the struct but pointed to by an internal pointer • Example: struct Student { char *FirstName; char *LastName; int StudentNum; double GradePointAvg; } Student S; S.FirstName = new char [40]; S.LastName = new char [40]; CSCD 326
Problems with Exogenous Data • In the previous example suppose we have: Student S, T; • if T has been initialized and had space allocated for its strings then: S = T; • does a member by member copy of T into S which means they have pointers to the same FirstName and LastName strings - thus: delete [] T.FirstName erases the string pointed to by S.FirstName • overriding the = operator and copying only pointers is a shallow copy • overriding the = operator and copying the memory holding characters is a deep copy CSCD 326
Linked List Basics • Arrays can be thought of as lists of objects which occupy contiguous memory • Using structures and pointers a list of objects which are located in non-contiguous memory can be built • the basic structure for such a list is shown below: struct Node Diagram: { char Element; Node *next; } Element Next CSCD 326
Linked List Building void main() { Node *head = NULL, *cur; char c; for(c = ‘a’; c <= ‘z’; c++) { if(!head) { head = cur = new Node; head->Element = c; } else { cur->Next = new Node; cur = cur->Next; cur->Element = c; } } cur->Next = NULL; } CSCD 326