1 / 86

HKUST Summer Programming Course 2008

HKUST Summer Programming Course 2008. Pointers and References ~ Pointers, Memory Allocation and References. Overview. Pointers What are Pointers? Declaration of Pointer Variables Pointer Operator - & (Address-Of) Pointer Operator - * (Dereference) The Different Uses of Operator *

brandy
Download Presentation

HKUST Summer Programming Course 2008

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. HKUST SummerProgramming Course 2008 Pointers and References ~ Pointers, Memory Allocation and References

  2. Overview • Pointers • What are Pointers? • Declaration of Pointer Variables • Pointer Operator - & (Address-Of) • Pointer Operator - * (Dereference) • The Different Uses of Operator * • Pointer Assignments • Pointer Arithmetic • Pointer Comparisons • Multiple Indirection (Pointer to Pointer) • Arrays and Pointers • Dereference Array Pointers • Array of Pointers • Const and Pointer • Null Pointer • void Pointer

  3. Overview • Memory Allocation • Static and Dynamic Allocation • De-allocation of Memory • Allocating and De-allocating Dynamic Arrays • Illegal Delete on Dynamic Arrays • Dangling Pointer • Memory Leakage • References • What are References? • The Different Uses of Operator & • Call by Reference • Pointer vs. Reference • Return-by-Reference

  4. Pointers and References Pointers

  5. What are Pointers? • A pointer or pointer variable is a VARIABLE that holds a memory address of another object (typically another variable) in memory. Memory Address Variables in memory If one variable contains the address of another variable, the first variable is said to point to the second. ‘a’ 1000 1004 1008 1000 1012 1016 Pointer / Pointer variable 1020 Memory

  6. Declaration of Pointer Variables • If a variable is going to hold an address of another variable, it must be declared as follows. SYNTAX: <type>* <name>; OR <type> *<name>; where type is the type of variable that this pointer variable can point to (e.g. int, char, double, user-defined type). The name is the name of the pointer variable. • Actually, we can treat <type>* as a special type which is a pointer type.

  7. Example // declare a pointer that points to a variable of int type int* a; // the value of a is undefined and contains garbage. // declare a pointer that points to a variable of double type double* b; // the value of b is undefined and contains garbage. // declare a pointer that points to a variable of char type char* c; // the value of c is undefined and contains garbage. // there is no difference for you to put * close to type // OR close to name int* d; // the value of d is undefined and contains garbage. int *d;

  8. Pointer Operator - & (Address-Of) • There are two special operators for pointers: & and * • The first operator, & is a unary operator that returns the memory address of another variable. • Usage: &<variable_name> • We can think of & as returning “the address of”. • Example: // pint receives the address of var1 int var1 = 5; int* pint = &var1; // pdouble receives the address of var2 double var2 = 1.23; double* pdouble = &var2; // ERROR: pdouble2 must point to a variable of type double double* pdouble2 = &var1;

  9. Pointer Operator - & (Address-Of) • Graphic representation of last example Memory Address Variables in memory Variables Name 5 1000 var1 1000 1004 pint 1012 pdouble 1008 1.23 var2 1012 1016 Memory

  10. Example - & (Address-Of) Memory Address Variables in memory Variables Name #include <iostream> using namespace std; int main(){ int a, b; a = 88; b = 100; cout << "The address of a is: " << &a << endl; cout << "The address of b is: " << &b << endl; return 0; } 1000 … a 1004 88 b 100 1008 … 1012 Memory Output: The address of a is: 1004 The address of b is: 1008

  11. Pointer Operator - * (Dereference) • The second operator, *, is the complement of operator &. • It is also aunary operator that accesses the value located at the address that it points to. • We can think of * as “at address”. • Example: int var1 = 5; // if (&var1) = 1004 int* pint = &var1; // pint points to var1 (then, pint = 1004) // var2 receives the value at address pint (var2 = 5). int var2 = *pint; // change the value of the memory location pointed to by pint // to 10, therefore var1=10, but note that var2=5 *pint = 10;

  12. Pointer Operator - * (Dereference) • Graphic representation of last example Note that there is no guarantee that two variables are stored consecutively, even if they are defined consecutively. Memory Address Variables in memory Variables Name 5 10 1000 var1 1000 1016 pint 5 1020 var2 1024 Memory

  13. The Different Uses of Operator * • Do not confuse the use of dereference operator * versus the * as a part of a pointer type. • Example: int* p; // this means to declare a pointer variable int i,j=10; p = &j; i = *p; // this means to dereference the variable p

  14. Pointer Assignments • As with any variable, you may use a pointer variable on the right-hand side of an assignment statement to assign its value to another address. • Example: int main(){ int x = 1; int *p1, *p2; // remember to add a * before p2 p1 = &x; // address of x is assigned to p1 p2 = p1; // content of p1 (which is address of x) // is assigned to p2 *p2 = 100; cout << "The address of x: " << p2 << “, x = ” << x << endl; return 0; }

  15. Example on Pointers Output: value1=10, value2=20 int main (){ int value1 = 5, value2 = 15; int *p1, *p2; // why not int* p1, p2? p1 = &value1; // p1 = address of value1 p2 = &value2; // p2 = address of value2 *p1 = 10; // value pointed to by p1=10 *p2 = *p1; // value pointed to by p2= value // pointed to by p1 p1 = p2; // p1 = p2 (pointer value copied) *p1 = 20; // value pointed to by p1 = 20 cout << "value1=" << value1 << “, value2=" << value2; return 0; }

  16. Example – Swap Two Elements void indirect_swap(char* ptr1, char* ptr2){ char temp = *ptr1; *ptr1 = *ptr2; *ptr2 = temp; } int main() { char a = 'y'; char b = 'n'; indirect_swap(&a, &b); cout << a << “” << b << endl; return 0; }

  17. Pointer Arithmetic • There are ONLY two arithmetic operations that you may use on pointers: Addition and Subtraction. • Therefore, you can use +, -, ++, --, +=, -=. • No multiplication nor division. • To understand what occurs in pointer arithmetic, let p1 be an integer pointer with current value of 2000. Also, assume integers are 4 bytes long. After the expression p1++, • p1 contains 2004, NOT 2001. • The same is true of decrements. For example, assuming that p1 has the value 2000, the expression p1-- causes, • p1 to have the value 1996.

  18. Pointer Arithmetic • Graphic representation of last example Memory Address Variables in memory Variables Name 2000 p1 p1-- 200 1996 100 2000 p1++ 300 2004 Memory

  19. Pointer Arithmetic • Generalizing from the preceding example, the following rules govern pointer arithmetic. • Each time a pointer is incremented, it points to the memory location of the next element of its base type. • Each time a pointer is decremented, it points to the location of the previous element. • When applied to character pointers, this will appear as “normal” arithmetic because characters are 1 byte long. • All other pointers will increase or decrease by the length of the data type they point to. • Eg. The size of a double variable is 8 bytes.

  20. Pointer Arithmetic • You are not limited to the increment and decrement the pointer by one. • For example, you may add or subtract integers to or from pointers. • The expression p1 = p1 + 2; makes p1 point to the second element of p1’s type beyond the one it currently points to. • The expression p1 = p1 - 2; makes p1 point to the second element of p1’s type precede the one it currently points to.

  21. Pointer Arithmetic Memory Address Variables in memory Variables Name 2004 p1 int* p1 = 2004; p1-2 1996 2000 p1+2 2004 2008 2012 Memory

  22. Pointer Comparisons • We can compare two pointers in a relational expression. • For instance, given two pointers, p and q, the following statements are perfectly valid. if(p < q) cout << "p points to lower memory than q" << endl; if(p > q) cout << "p points to higher memory than q" << endl; if(p == q) cout << "p points to the same memory as q" << endl;

  23. Multiple Indirection (Pointer to Pointer) • You can have a pointer point to another pointer that points to the target value. • This is called “multiple indirection” or “pointer to pointer”. • Pointers to pointers can be confusing. The figure below helps clarify the concept of multiple indirection. Pointer variable Variable address value Single Indirection Pointer variable Pointer variable Variable Multiple Indirection address address value

  24. Multiple Indirection (Pointer to Pointer) • The value of a normal pointer is the address of the object that contains the value. • In the case of pointer to pointer, the first pointer contains the address of second pointer, which points to the object that contains the value desired. • A variable that is a pointer to pointer can be declared as: SYNTAX: <type>** <name>; • Example: int i = 10; int* ptr = &i; int** p_ptr = &ptr; int *q = ptr, **r = &ptr;

  25. Multiple Indirection (Pointer to Pointer) • Multiple indirection can be carried on to whatever extent required, but more than a pointer to a pointer is rarely needed. • In fact, excessive indirection is difficult to follow and prone to logical errors.

  26. Example – Multiple Indirection Memory Address Variables in memory Variables Name int a = 80; int *p = &a; int **q = &p; int ***r = &q; cout << a << " "; cout << *p << " "; cout << **q << " "; cout << ***r << " "; a 80 1000 1000 p 2000 q 2000 2004 2004 r 2008 2012 Output: 80 80 80 80 Memory

  27. Arrays and Pointers • There is a close relationship between pointers and arrays. • An array name is actually a CONSTANT pointer to the first element of the array. A constant pointer means we cannot change the value of the pointer variable (it cannot point to another location). • Example: int main (){ // Demonstrate array name is a constant pointer int a[5]; cout << "Address of a[0]: " << &a[0] << endl << "Name as pointer: " << a << endl; return 0; } Output: Address of a[0]: 0x0065FDE4 Name as pointer: 0x0065FDE4

  28. Problem • Can we do something like the following? • int a = 10; int* p = &a; int A[6] = {0,2,4,8,10,12}; A = p;  Can we do this? • No! Since A is a constant pointer.

  29. Arrays and Pointers Memory Address Variables in memory Variables Name // defines an array of integers int A[6] = {0,2,4,8,10,12}; int* p; p = A; // p points to A[0]; • Since array names and pointers are equivalent, we can also use p as the array name. • For example p[3] = 7; or *(p+3) = 7; is equivalent to A[3] = 7; 2000 p 0 2000 A[0] 2 2004 A[1] 4 A[2] 2008 8 7 A[3] 2012 2016 A[4] 10 12 2020 A[5] Memory

  30. Example - Arrays and Pointers Memory Address Variables in memory Variables Name #include <iostream> using namespace std; int main(){ int A[6] = {2,4,6,8,10,22}; int *p = &A[1]; //int *p = A+1; // more efficient cout << A[0] << " " << p[-1]; cout << " "; cout << A[1] << " " << p[0]; return 0; } 2004 p p[-1] 2 2000 A[0] 4 2004 A[1] p[0] 6 2008 A[2] 8 2012 A[3] 10 2016 A[4] 22 2020 A[5] Output: 2 2 4 4 Memory

  31. Pass-by-Array (new slide) • We can pass an array as a parameter into a function by two methods. void func1( double array[ ], int size ); void func2( double* array, int size ); int main( ) { double score[] = {1, 2.5, 6, 8.5}; func1(score, 4); func2(score, 4); return 0; } • Both methods pass an array of type double into the function. • C++ passes in the address of the first element of the array. • Hence, we should pass in the size, to indicate the end of the array.

  32. Pass-by-Array (new slide) • Indeed, there is no pass-by-array in C++. • It is implemented by pass-by-value. But this time, it pass the address (of the first element) by value. • Even if you change the pointer array to point to another array, the variable score is still pointing to the same array, without change (since it is pass-by-value). • However, you can directly modify the content of the array, which is pointed to by both pointers array and score. • The modification to the content of the array can affect the array score defined in the main function.

  33. Pass-by-Array void inputToArray( double* array, int size ) { for (int i=0; i<size; i++) cin >> array[i]; } void print( const double* array, int size ) { for (int i=0; i<size; i++) cout << array[i] << endl; } int main( ) { double score[10]; inputToArray( score, 10 ); print( score, 10 ); return 0; } • This will reset the content of the array with the input from keyboard and then print it to the screen. • The keyword const will be covered in a minute.

  34. Character String • Character string is indeed a character array. • Recall that “Hello World” is of the type const char[12] • We can pass this into some function with parameter type const char* • Eg. char* strcpy(char* dest, const char* src) • We can pass “Hello World” into the second parameter src, but not dest. • However, the following definitions are different: • char message1[12] = “Hello World”; • “Hello World” is indeed a character array stored in a constant data area (cannot be modified). • message1 is a character array, initialized by “Hello World”. • You can modify message1, say: message1[0] = ‘a’; • char* message2 = “Hello World”; • message2 is simply a pointer, pointing to that constant data area. • No separate array is allocated for storing “Hello World”. • You cannot modify through this pointer, say: message2[0] = ‘a’; • Otherwise, runtime error will be resulted.

  35. Dereference Array Pointers • As array name is a constant pointer, dereference operator (*) can be used on it. • A[0] is same as *(A+0) • A[1] is same as *(A+1) • A[2] is same as *(A+2) • In general, A[n] is equivalent to *(A+n)

  36. Array of Pointers • Pointers may be arrayed like any other data type. • Example: int main(){ int a = 1, b = 2, c = 3; // array of pointers int *p[3]; p[0] = &a; p[1] = &b; p[2] = &c; return 0; } Memory Address Variables in memory Variables Name 1 2000 a 2 2004 b 3 c 2008 p[0] 2000 2012 2004 p[1] 2016 2008 2020 p[2] Memory

  37. Const and Pointer • When using a pointer, two objects are involved: the pointer itself, and the variable it is pointing to. • The syntax for pointers to constants and constant pointers can be confusing . The rule is that • any const to the left of the * in a pointer type refers to the object pointed to; • any const to the right of the * refers to the pointer itself. • The above rules are valid if you are considering single indirection. • It may be a little bit more complicated if multiple indirection is considered. • However, we won’t cover this in this course.

  38. Example1 - Const and Pointer char c = ‘Y’, d = ‘N’; // constant pointer (must be initialized), cpc = &d is invalid char *const cpc = &c; // pointer to a constant char, *pcc = ‘H’ is invalid char const* pcc = &c; const char* pcc2; // may not be initialized immediately // constant pointer points to a constant char (must be // initialized), both cpcc = &d and *cpcc = ‘H’ are invalid const char *const cpcc = &c; char const *const cpcc2 = &c;

  39. Example2 - Const and Pointer int main(){ char s[] = “Ming”; // type of “s” ~~ char *const char p[] = “Adam”; // type of “p” ~~ char *const const char* pcc = s; // Pointer to constant char pcc[0] = ‘5’; // Error! s[0] = ‘5’; // Fine! pcc = p; // OK, but what does that mean? char *const cpc = s; // Constant pointer cpc[0] = ‘5’; // OK cpc = p; // Error! // Constant pointer to constant char const char *const cpcc = s; cpcc[0] = ‘5’; // Error! cpcc = p; // Error! return 0; }

  40. Example3 - Const and Pointer • It is an error if you try to use a “pointer to non-const object” to point to a “constant object”. • Imagine that you can always modify the value indirectly through the “pointer to non-const”. • You may then modify a constant object through using a pointer to point to it. int m = 10; // normal object const int N = 100; // constant object int* p = &m; // OK p = &N; // ERROR *p = 1000; // OK const int* q = &N; // OK *q = 1000; // ERROR

  41. Example4 - Const and Pointer • You cannot assign “pointer to const” to a “normal pointer” • Although it is valid to use a “pointer to const” to point to a non-constant object • To check which object (const or non-const) a pointer is pointing to need trace the code • C++ compiler won’t do this, so it simply disallow this type of assignment. int i = 151; int* pi = &i; // pi is a “normal pointer” const int* pic = &i; // pic is a “pointer to const” pi = pic; // Error! Cannot convert from // ‘const int*’ to `int *’, // although i is modifiable

  42. NULL Pointer • A null pointer is a special pointer that is currently pointing to nothing. • Often pointers are set to zero (or predefined constant NULL) to make them null pointers, or tested against zero (or NULL) to see if they are null. Example: int* p = 0; if(p) // 0 (or null) is treated as false cout << "p is not a null pointer" << endl; int* p = NULL; if(p==NULL) cout << "p is a null pointer" << endl;

  43. NULL Pointer • We will get an error if we try to dereference a NULL pointer. • Example #include <iostream> using namespace std; int main(){ int *p; p=NULL; cout << p << endl; // prints 0 cout << &p << endl; // prints address of p cout << *p << endl; // Error! return 0; }

  44. void Pointer • Recall that int* can only point to a variable of type int. It cannot point to a variable of type double. • void pointer is a special pointer that can point to anything. • void pointer is of the type void* • Note that void is not a datatype itself. • It can point to any datatype. • Example: int n = 10; double x = 1.2; int* p_n = &n; void* p = &n; // point to int void* p = &x; // point to double void* p = &p_n; // point to an “integer pointer”

  45. void Pointer • However, since void pointer can point to anything, the length of its base type is unknown. • We cannot use addition nor subtraction, whose result depends on the length of its base type. • Also, we cannot interpret the result what it is pointing to. • We cannot use dereference operator. • We must first cast the void pointer to the “normal” pointer before using the dereference operator. int n = 10; void* p_n = &n; cout << *((int*)p_n) << endl; // output 10 cout << *((double*)p_n) << endl; // output garbage

  46. void Pointer • Recall that C++ is a strongly-typed programming language. • The advantage is that the compiler can detect many type mismatch errors. • void pointer prevent the compiler from checking the type. • The compiler never knows whether casting a void pointer to a “double pointer” (or an “integer pointer”) is valid or not. • It is not recommended to use it in your programming. • However, some C-styled functions make use of the advantage of void pointer that it can point to anything. • You may find that some standard functions may take a void pointer as input. • Some GUI programming also use void pointer. • However, this is far outside our scope.

  47. Pointers and References Memory Allocation

  48. Memory Allocation • If we know prior to the execution of the program the amount of memory that we need, we can allocate memory statically prior to program start-up (i.e. compilation time).  We call this static memory allocation. • However, we cannot always determine how much memory we need before our program runs. • For example, the size of an array may not be known until your executing program determines what these values should be. • So, what should we do?  We need dynamic memory allocation.

  49. Memory Allocation • In C++, we can request memory from operating system at runtime and we call this dynamic memory allocation. • An area of memory called the heap (or free store) is available in the run-time environment to handle dynamic memory allocation. • In C++ programs, we can use operator new to allocate memory from heap and operator delete to release heap memory.

  50. Conceptual View of Memory • Heap is a special area of memory which is reserved for dynamic variables. MEMORY PROGRAM MEMORY code for functions DATA MEMORY global program heap (dynamic memory) system stack

More Related