CS 228 meeting -*- Outline -*- * pointers in C++ (HR 7.1-2, 7.4) ** pointer types (HR 7.1) --------------------------- POINTER TYPES A pointer type in C++ is written * Examples: int * int* float * int * * --------------------------- Q: does whitespace matter in this form? the last one shows that pointer types are themselves types, so int** is the type of pointers to pointers to ints *** declarations ---------------------------- POINTER VARIABLE DECLARATIONS Follow the standard declaration syntax. Examples: int* ip; int * intPtr; int * ip1, * ip2; int *ip3, i; int * pa[10]; ------------------------------ Q: what's the type of i? just like int ia[3], j; this is why some like to write the * next to the var name, best to declare each var in its own declaration [] has higher precedence than *, so pa is an array of 10 pointer variables *** operations ----------------------------- BASIC OPERATIONS ON char* POINTERS int main() { char c = 'a'; char *charPtr = &c; // dangerous char *dcp = 0; dcp = new char; *dcp = *charPtr; delete dcp; } -------------------------------- draw pictures of how this executes *** examples ---------------------------------- PROBLEM Implement the following specification void IntCellSwap(int* c1, int* c2) // PRE: c1 and c2 are valid pointers // MODIFIES: *c1, *c2 // POST: *c1 == *c2 // && *c2 == *c1 ---------------------------------- explain that a valid pointer is one that is not null (0) draw a picture of how this executes a call ---------------------------------- FOR YOU TO DO Implement the following specification (without using swap): int* IntCellMin(int* c1, int* c2, int* c3) // PRE: c1, c2, c3 are valid pointers // && *c1, *c2, and *c3 are distinct // POST: FCTVAL is a pointer to // the smallest of *c1, *c2, and *c3 ---------------------------------- note: you're not supposed to modify the cells could use const int* instead above Contrast this with finding the smallest pointer! Q: can you give a sample call? Can you draw pictures of it executing? *** summary of pointer ADT --------------------------------- SUMMARY OF BASIC POINTER OPERATIONS (for type char*) Operation Example Type 0 0 char* new new char char* & &c char* * *charPtr char = dcp = new char char* delete delete dcp; (void) ----------------------------- give the names of these: null pointer, address-of (&), dereference (*) give pictures to go with these Q: What's the opposite of &? Q: What would change if this were int*? Q: Why didn't we have anything like delete in Scheme? Note that defines NULL to be 0, many like to use that Note that its dangerous to take the address of a declared variable... ** constant pointer expressions and pointer arithmetic (HR 7.2) *** pointers to const objects vs. const pointer objects (DD 5.5) a better term might be pointers variables containing pointers to const objects vs. const pointer objects containing pointers to variables ------------------------------ POINTERS TO const OBJECTS USEFUL FOR FORMAL PARAMETERS An array of const int objects: int Minimum(const int arr[], int size) arr[i] is a const int object Pointers to const int objects: int IntCellMin(const int *c1, const int *c2) *c1 is -------------------------- ... a pointer to a const int object the call below is like IntCellMin(&v1, &v2) --------------------------- call: References to const int objects: int IntVarMin(const int & c1, const int & c2) ------------------------------ Q: what would a call of IntVarMin look like? ----------------------------- FOR YOU TO DO Given the following declarations: const float e = 2.73; float f = 7.4; const float pi = 3.14159; const float *pcf = π Draw a picture of these variables Which of the following are legal? Why? *pcf = 7.3; // (a) *pcf = e; // (b) pcf = &e; // (c) pcf = &f; // (d) ------------------------------ only (c) and (d) are legal (d) is legal because of subtyping (ok to not permit changes) *** constant pointer expressions -------------------------------- const POINTER OBJECTS NOT USEFUL FOR FORMAL PARAMETERS A const pointer to an int: int *const unchangingPtr = new int; Can do: *unchangingPtr = 3; Cannot do: unchangingPtr = &i; -------------------------------- -------------------------------- const POINTER OBJECTS vs. POINTERS to const OBJECTS vs. const POINTER OBJECTS to const OBJECTS int *const nochangePtr = new int; const int *nochangeCellPtr; const int *const nochangePtrToNochange = nochangePtr; -------------------------------- Q: what is a constant int expression? ------------------------------- CONSTANT POINTER EXPRESSIONS def: a *constant pointer expression* is an expression that denotes a pointer and that is known before run-time. Examples: 0 noChangePtr // if has type int *const &vec[0] // if vec is an array vec // if vec is an array ------------------------------- *** pointers and arrays (HR 7.2, DD 5.8-9) draw a picture to go with the following, being sure not to put myStr on a box! emphasize that s doesn't allocate storage for chars, but a pointer. ----------------------------- ARRAY NAMES ARE CONSTANT POINTER EXPRS Fact: given the declarations char myStr[5] = "abcd"; char *s = myStr; equivalent expressions: myStr[3] s[3] *(s+3) *(myStr+3) ----------------------------- Q: what's the type of these? ----------------------------- equivalent statements: myStr[0] = 'y'; *(myStr+0) = 'y'; *myStr = 'y'; *s = 'y'; *(s+0) = 'y'; s[0] = 'y'; illegal: myStr++; myStr = myStr + 1; ------------------------------ Q: why? because to be changed, need to have a box ---------------------------------- SOME HELPFUL TERMINOLOGY def: an *lvalue* is an expression that ---------------------------------- ... denotes an object (or a function) "l" means it can appear on the "left" of an assignment but that's not a good definition, as const objects can't but are lvalues, as are function names ---------------------------------- Key characteristic: can take the address of an lvalue &myVar, &(*(p+3)) examples: ---------------------------------- variable names dereferences of valid pointers Q: what other examples are there? array elements, fields of a struct or union function names Q: is the name of a const an lvalue? yes ---------------------------------- Not an lvalue: array names ---------------------------------- it's an rvalue Q: is the number 3 an lvalue? the char literal 'c'? Other examples: float literals, string literals, pointers! *** pointer arithmetic (HR 7.2, DD 5.7) ----------------------------- POINTER ARITHMETIC You can: add pointer and int p + 1 subtract pointer and int p - 1 use assignment ops p += 3, p++ with + and - and ints p -= 2, --p MEANING long int arr[5] = {0, 1, 2, 3, 4}; long int *p = myArr; hardware C++ Memory Program Address Cell Identifier Type 3000 [ 0 ] arr[0] long int 3004 [ 1 ] arr[1] long int 3008 [ 2 ] arr[2] long int 3012 [ 3 ] arr[3] long int 3016 [ 4 ] arr[4] long int 3020 [ 3000 ] p long int * ------------------------------------------- show what the pointer p+1 is draw another picture with this arrow in it. show what the effect of p+=3 is ------------------------------------------- POINTERS ARE *NOT* INTEGERS You cannot: use multiplication p*3 division, mod, etc. p/4, p%2 POINTERS CAN BE COMPARED However, you can: compare pointers to 0 p == 0, p != 0, !p compare pointers into the same array double coefs[100]; double *p1 = &coefs[10]; double *p2 = coefs + 20; p1 < p2, p2 > p1, p2 >= p1 p1 <= p2, p1 == p1, p1 != p2 ----------------------------- *** examples ------------------------------- PROBLEM Implement the following specification: char* strcat(char *to, const char *from) // PRE: to and from are null-terminated // && to points to enough space // MODIFIES: to[strlen(to) // ..strlen(to)+strlen(from)] // POST: FCTVAL == to && chars in from // are copied into the end of to ------------------------------- do this using pointer arithmetic { for (char *p = to; *p != '\0'; p++) { ; } // ASSERT: p points to the first null in to strcpy(p, from); return to; } ------------------------------ FOR YOU TO DO An error: char myName[] = "Gary"; myName = "Fred"; // error What does this do? char *str = myName; str = "Fred"; Implement the following specification: char* strcpy(char *to, const char *from) // PRE: to and from are null-terminated // && to points to enough space // MODIFIES: to[0..strlen(from)] // POST: FCTVAL == to && chars in from // are copied into to including the '\0' ------------------------------ do this using pointer arithmetic // strcpy.C #include "strcpy.h" char* strcpy(char *to, const char *from) { char *p; char *q; p = to; q = from; // INV: p is a valid pointer in the array starting at to, // q is a valid pointer in the array starting at from, // the characters from from to q-1 have been copied to p in order. while (*q != '\0') { *p = *q; p++; q++; } // ASSERT: all the characters are copied except the null character. *p = '\0'; return to; } then show the array notation equivalent *** the truth about arrays ------------------------------- THE TRUTH ABOUT PASSING ARRAYS AS PARAMETERS An array name is a constant pointer expression. Arrays are in effect passed by reference, because ------------------------------- ... their names are pointers values, which are passed by value. Q: So how are strings passed in C++? --------------------------------- Equivalent for clients: char* strcpy(char *to, const char *from) char* strcpy(char to[], const char from[]) The only difference is in definitions: char *s; char str[10]; --------------------------------- Q: Can you draw a picture of the last two definitions? ** pointers vs. references (HR 7.4, DD 5.6) *** example -------------------------------- POINTERS vs. REFERENCES // using references void assign2(int& v1, int& v2, int e1, int e2) { v1 = e1; v2 = e2; } // using pointers void assign2(int *v1, int *v2, int e1, int e2) { *v1 = e1; *v2 = e2; } int main() { int i = 3; int j = 4; // call using reference version assign2(i, j, j+1, i+1); // call using pointer version assign2(&i, &j, j+1, i+1); } ------------------------------ Q: Which is more convenient? Which is more error prone? references are implemented using addresses, but that is hidden from the programmer *** differences and usage draw a picture of the following ------------------------------------- DIFFERENCES BETWEEN REFERENCES AND POINTER VARIABLES int i = 5; int j = 6; int& ri = i; int *pi; pi = &i; pi = &j; reference pointer var separate variable? no yes can be changed no yes must be initialized yes no WHEN TO USE EACH pass-by-reference references loops pointer variables data that may change pointer variables -------------------------------------