Pointers References Why Pointers Efficiency avoid passbyvalue overhead

Pointers & References

Why Pointers? Efficiency avoid pass-by-value overhead Relationships connections between objects recursive data structures separate interface and implementation Machine-level programming controls hardware

Pointers in C++ Pointer basics Incomplete Types Pointer-related typedef’s Pointers and const Pointers and arrays References

What is a Pointer? An address actually, a variable that holds an address Actual numeric address not important except in embedded programming

// address. cpp: Illustrates the address-of op (&) #include <iostream> using namespace std; int main() { int i = 7, j = 8; cout << "i == " << i << ", &i == " << &i << endl; cout << "j == " << j << ", &j == " << &j << endl; } /* Output: i == 7, &i == 0012 FF 88 j == 8, &j == 0012 FF 84 */

Pointer Declarations Use an asterisk (*) int* p; “p is a pointer to an int” Must indicate type pointed to pseudo-exception: void * ▪ the only thing you can do with a void* is hold it

Pointers to Pointers Multiple levels of indirection Occasionally use multiple indirection levels Given int ** p; … **p is an int => *p is a pointer to an int => p is a pointer to an int

// ptr 2 ptr. cpp: Pointers to pointers #include <iostream> using namespace std; int main() { int i = 7; int* ip = &i; int** ipp = &ip; } cout << << cout << "Address " << ip << " contains " << *ip endl; "Address " << ipp << " contains " << *ipp endl; "**ipp == " << **ipp << endl; // Output: Address 0012 ff 88 contains 7 Address 0012 ff 84 contains 0012 ff 88 **ipp == 7

Pointer Arithmetic Adding or subtracting an int Moves the pointer up (+) or down (-) in memory that number of objects i. e. , p+n increases address by n*sizeof(*p) Can only be used within an array!!! you can move one past the end but you can’t dereference there

Subtracting Pointers Yields number of objects between two objects Could be negative Special type to hold result: ptrdiff_t Usually a typedef for long ptrdiff_t d = q – p;

About typedef “Type definition” Creates synonyms for existing types For convenience and portability Used heavily in STL typedef typedef char my. Char; unsigned int wchar_t; long ptrdiff_t; unsigned long size_t; int A 5[5]; A 5 a; // Same as int a[5]
![int main() { float a[] = {1. 0, 2. 0, 3. 0}; cout << int main() { float a[] = {1. 0, 2. 0, 3. 0}; cout <<](http://slidetodoc.com/presentation_image_h2/abf1865d32b31c62c6c0a8ef0946da66/image-12.jpg)
int main() { float a[] = {1. 0, 2. 0, 3. 0}; cout << "sizeof(float) == " << sizeof(float) << endl; float* p = &a[0]; // or just a; cout << "p == " << p << ", *p == " << *p << endl; ++p; cout << "p == " << p << ", *p == " << *p << endl; // Subtract two pointers: ptrdiff_t diff = (p+1) - p; cout << "diff == " << diff << endl; diff = reinterpret_cast<char*>(p+1) reinterpret_cast<char*>(p); cout << "diff == " << diff << endl; } /* Output: sizeof(float) == 4 p == 0 x 7 fff 5 fbff 8 f 0, *p == 1 p == 0 x 7 fff 5 fbff 8 f 4, *p == 2 diff == 1 diff == 4 */

Pointers and const Two degrees of freedom: Is the pointer itself const? Or is the thing pointed to const? Usually the latter case (“pointer-to-const”) All depends on where you put the const Relative to the asterisk Used extensively throughout the C library

Pointers and const before the asterisk ⇒ const contents “p is a pointer to a const int” const after the asterisk ⇒ const pointer “p is a const pointer to an int” const char * char const * char * const char * p 1; // *p 1 = ‘c’ illegal; ++p 1 OK p 1; // (same as above) p 2; // *p 2 = ‘c’ OK; ++p 2 illegal const p 3 = "fixed"; // neither (not useful)

Assigning non-const to const Always okay (no loss of safety) Example: char* p; … const char* q = p; ▪ p doesn’t care if you modify it; but q won’t anyway Many char* arguments in the C library are const Going the other way (const to non-const) loses safety; should be rare and requires a cast

Assigning const to non-const Not allowed (loses const protection) Should be rare and requires a cast: const char * p = …; char* q = const_cast<char*>(p); *q = …;

Multiple Indirection and const A “dark corner” Cannot convert char** to const char** Must add const at all levels to the left of the right-most star: we’re protecting the contents, not the pointer const char * const * Example: multconst. cpp, multconst 3. cpp

Generic Pointers void * Allows holding a pointer to any type Must explicitly cast back to original type to use Used often for function parameters Useful for: treating any object as a sequence of bytes implementing low-level, generic containers

Implementing memcpy( ) void* memcpy(void* target, const void* source, size_t n) { // Copy any object to another char* targetp = static_cast<char*>(target); const char* sourcep = static_cast<const char*>(source); while (n--) *targetp++ = *sourcep++; return target; } int main() { float x = 1. 0, y = 2. 0; memcpy(&x, &y, sizeof x); cout << x << endl; } // same as x = y // 2

Another void* example inspect( ) function Prints the bytes of any object Receives a void* parameter Actually const void* Converts to a const char* to inspect bytes actually const unsigned char* for hexadecimal printing

int main() { char c = 'a'; short i = 100; long n = 100000 L; double pi = 3. 141529; char s[] = "hello"; } inspect(&c, sizeof c); inspect(&i, sizeof i); inspect(&n, sizeof n); inspect(&pi, sizeof pi); inspect(s, sizeof s); // Output: byte 0: 61 byte 0: 1: 64 00 byte 0: 1: 2: 3: a 0 86 01 00 byte byte 0: 1: 2: 3: 4: 5: 6: 7: 13 7 c d 3 f 4 d 9 21 09 40 byte byte 0: 1: 2: 3: 4: 5: 68 65 6 c 6 c 6 f 00 cout cout << << << endl; endl;

// inspect. cpp: Inspect the bytes of an object #include <iostream> #include <iomanip> using namespace std; void inspect(const void* ptr, size_t nbytes) { const unsigned char* p = static_cast<const unsigned char*>(ptr); } cout. setf(ios: : hex, ios: : basefield); for (int i = 0; i < nbytes; ++i) cout << "byte " << setw(2) << setfill(' ') << i << ": " << setw(2) << setfill('0') << int(p[i]) << endl;

Yet Another void* Example Illustrates C’s qsort function which you may never need to use! Illustrates casting a void* to an int See sortints. cpp See also sort. Strings. cpp, sort. Strings 2. cpp

Incomplete Types To introduce a pointer to a type that hasn’t yet been fully defined For example, the mutual reference problem: class A; class B {A* a; …}; class A {B* b; …}; Another example: p. Impl idiom “pointer to implementation”

Hiding Implementation Using an Incomplete Type (Stack. Impl) // Stack. h class Stack. Impl; class Stack { Stack. Impl* p. Impl; public: void push(int); int pop(); int top() const; int size() const; }; // Stack. cpp class Stack. Impl { …}; int Stack: : push(int x) { p. Impl->data[n++] = x; } …

Pointers and Arrays Array names in expression “decay” into a pointer to the 1 st element Except when an operand to sizeof a is the same as &a[0] ⇒ *a == a[0] ⇒ a + i == &a[i] ⇒ *(a + i) == a[i] ▪ *(p + i) == p[i] // for any pointer

Implementing strcpy( ) // Arrays are passed to strcpy char* strcpy(char* dest, const char* source) { char* save = dest; while (*dest++ = *source++) // Note '=' ; return save; }
![Array Size Idiom Given int a[n]; // where n is const n == sizeof Array Size Idiom Given int a[n]; // where n is const n == sizeof](http://slidetodoc.com/presentation_image_h2/abf1865d32b31c62c6c0a8ef0946da66/image-28.jpg)
Array Size Idiom Given int a[n]; // where n is const n == sizeof a / sizeof a[0] Computes at compile time! Only valid when the array definition is in scope Can’t work for array function parameters Not the most useful idiom, admittedly
![Multi-dimensional Arrays Don’t really exist! “Arrays of arrays” model int a[2][3] an array of Multi-dimensional Arrays Don’t really exist! “Arrays of arrays” model int a[2][3] an array of](http://slidetodoc.com/presentation_image_h2/abf1865d32b31c62c6c0a8ef0946da66/image-29.jpg)
Multi-dimensional Arrays Don’t really exist! “Arrays of arrays” model int a[2][3] an array of 2 elements each element is an arrays of 3 ints what is sizeof(a[0])?

Question How do you declare a pointer, p, for the following: ? ? ? = new int[2][3]; Remember: arrays are one-dimensional Remember also: new returns a pointer to the first element of the requested array
![Higher and Deeper Repeat the process on the 3 -d array: int a[2][3][4]; Higher and Deeper Repeat the process on the 3 -d array: int a[2][3][4];](http://slidetodoc.com/presentation_image_h2/abf1865d32b31c62c6c0a8ef0946da66/image-31.jpg)
Higher and Deeper Repeat the process on the 3 -d array: int a[2][3][4];

Returning Heap Arrays Not often done As usual, must return a pointer to the first element So… what is the signature of the function? “f is a function that returns a pointer to an array of 3 ints” See ret 2 d. cpp

Pointers to (non-static) Members Conceptually similar to regular pointers a “pointer-like thing” referring to member of an object But they’re different really just type-safe offsets ▪ into an object or a function table they require an object to act upon See Lab 1

Review Specs for Program 1

How does istream: : get work? char c; cin. get(c); // reads next input byte into c cout << c; // prints the byte read as a char

References Can be function parameters Implements “call by reference” Can also be local Merely another name (alias) for an existing variable Can be return values Used by operator[ ]

References are Aliases #include <iostream> int main() { using namespace std; int i = 7; int& r = i; ++r; cout << i << endl; } // 8

Reference Parameters Implicit Pointer Indirection #include <iostream> using namespace std; void swap(int& x, int& y) { int temp = x; x = y; y = temp; } int main() { int i = 1, j = 2; } swap(i, j); cout << "i == " << i << ", j == " << j; /* Output: i == 2, j == 1 */

Reference Parameters Transparent access to argument void f(int x) {cout << &x << endl; } void g(int& x) {cout << &x << endl; } int main() { int n; cout << &n << endl; f(n); g(n); } /* Output: 0 x 7 fff 5 fbff 9 ac 0 x 7 fff 5 fbff 98 c 0 x 7 fff 5 fbff 9 ac */
![Reference Returns Must refer to a non-local object #include <iostream> int a[4] = {0, Reference Returns Must refer to a non-local object #include <iostream> int a[4] = {0,](http://slidetodoc.com/presentation_image_h2/abf1865d32b31c62c6c0a8ef0946da66/image-40.jpg)
Reference Returns Must refer to a non-local object #include <iostream> int a[4] = {0, 1, 2, 3}; int index = 0; int& current() { return a[index]; } // Returns a reference int main() { using namespace std; current() = 10; // replace a[0] index = 3; current() = 20; // replace a[3] for (int i = 0; i < 4; ++i) cout << a[i]; cout << endl; } /* Output: 10 1 2 20 */

Looking Deeper A reference is like a pointer that applies & and * automatically when needed It can be used on either side of an assignment On the left, it is an lvalue ▪ Writes to memory On the right it is an rvalue ▪ Reads from memory See returnref. cpp

const Reference Parameters When you won’t be changing the value The “best of both worlds” Efficiency of call-by-reference Safety of call-by-value (Almost) Always pass objects by (const) reference

An Employee Class class Employee { string name; double rate; double time. Worked; public: Employee(const string& ename, double erate) : name(ename) { rate = erate; } string get. Name() const double get. Rate() const double get. Time. Worked() const }; {return name; } {return rate; } {return time. Worked; } void record. Time(double etime) {time. Worked = etime; } double compute. Pay() const;

double Employee: : compute. Pay() const { const double& hours = time. Worked; if (hours > 40) return 40*rate + (hours - 40)*rate*1. 5; else return rate * hours; } int main() { using namespace std; Employee e("John Hourly", 16. 50); e. record. Time(52. 0); cout << e. get. Name() << " gets ” << e. compute. Pay() << endl; } John Hourly gets 957. 00

Example: hold. Ints. cpp Reads an arbitrarily large number of ints from a file into an expandable array Shows how to automatically grow a dynamic array Uses a reference argument to “return” the dynamic array from a function The return value is already used to indicate the number of ints read
- Slides: 45