700 likes | 855 Views
Pointers. CSCI 3333 Data Structures. by Dr. Bun Yue Professor of Computer Science yue@uhcl.edu http://sce.uhcl.edu/yue/ 2013. Acknowledgement. Mr. Charles Moen Dr. Wei Ding Ms. Krishani Abeysekera. Assumptions. Assume that you are familiar with C, C++ or Java. Brief Facts About C++.
E N D
Pointers CSCI 3333 Data Structures byDr. Bun YueProfessor of Computer Scienceyue@uhcl.eduhttp://sce.uhcl.edu/yue/2013
Acknowledgement • Mr. Charles Moen • Dr. Wei Ding • Ms. Krishani Abeysekera
Assumptions • Assume that you are familiar with C, C++ or Java.
Brief Facts About C++ • Evolved from C • Designed and implemented by Bjarne Stroustrup at the Bell Labs in the early 1980s • “C with classes”, Better C • Standardized by ISO in 1997 • Includes the C++ standard library • Standard Template Library (STL) • Part of the C++ standard library • Ready made classes for data structures and algorithms
C++ Filenames • Can be different from the name of the class or the name of the function in the file • .cpp • Extension for the C++ source code files • .h • Extension for C++ header files • Usually, code for a data structure is put in a header file, and then it can be added to a program with an include directive, e.g. #include "BasicVector.h" • Name of executable file • In MSVS it’s the name of your project • In g++ it’s either “a.out” or a name you specify
A Simple C++ Example /* FILE: main.cpp */ #include <iostream> #include <string> using namespace std; int main() { cout << "Enter your first name: "; string name; cin >> name; cout << "Hello, " << name << endl; return 0; //optional }
Comment C++ header files from C++ standard library Namespace for C++ standard library “Entry” function All C++ statements end with a semicolon A Simple C++ Example /* FILE: main.cpp */ #include <iostream> #include <string> using namespace std; int main() { cout << "Enter your first name: "; string name; cin >> name; cout << "Hello, " << name << endl; return 0; //optional }
Memory Address • Every byte in the primary memory has an address. • In C++, a pointer is a variable that stores a memory address. • The address (reference) operator & is used to return the address of a variable.
Pointer Type • A pointer variable has a type associated with it, and the memory address it points to should hold data of that type. int myInt = 0; // Allocates memory; stores 0 int *pMyInt; // Declares pointer variable without // initialization
An Example #include <iostream> #include <string> using namespace std; int main() { int x = 10; float y = 3.14159; string z = "I am a college professor."; bool b = true; cout << "x: value: " << x << " addr: " << &x << endl; cout << "y: value: " << y << " addr: " << &y << endl; cout << "z: value: " << z << " addr: " << &z << endl; cout << "b: value: " << b << " addr: " << &b << endl; }
Output x: value: 10 addr: 0012FF50 y: value: 3.14159 addr: 0012FF44 z: value: I am a college professor. addr: 0012FF1C b: value: 1 addr: 0012FF13
Pointer Type Checking • A pointer variable of a particular type cannot store address of an incompatible type. Error: int x = 10; float* fp_x = &x; MS VS: “Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast”
Dereferencing • Dereferencing (indirection) operation in C++: *. *p: access the value of the memory address stored in p. • * is heavy overloaded in C++: • Number multiplication • Pointer variable declaration • Dereferencing.
Example … int main() { int x = 10; cout << "value of x = " << x << endl; int* p_x = &x; cout << "value of p_x = " << p_x << endl; int** p_p_x = &p_x; cout << "value of p_p_x = " << p_p_x << endl; int*** p_p_p_x = &p_p_x; cout << "value of p_p_p_x = " << p_p_p_x << endl; *p_x = 15; cout << "value of x = " << x << endl; }
Output of Example value of x = 10 value of p_x = 0012FF60 value of p_p_x = 0012FF54 value of p_p_p_x = 0012FF48 value of x = 15
Example // Dereferencing: cout << "value of *p_x = " << *p_x << endl; cout << "value of *p_p_x = " << *p_p_x << endl; cout << "value of **p_p_x = " << **p_p_x << endl; cout << "value of *p_p_p_x = " << *p_p_p_x << endl; cout << "value of **p_p_p_x = " << **p_p_p_x << endl; cout << "value of ***p_p_p_x = " << ***p_p_p_x << endl;
Output of Example value of *p_x = 10 value of *p_p_x = 0012FF60 value of **p_p_x = 10 value of *p_p_p_x = 0012FF54 value of **p_p_p_x = 0012FF60 value of ***p_p_p_x = 10
Example: Same Effect … int main() { int x = 10; cout << "value of x = " << x << endl; int* p_x = &x; cout << "value of p_x = " << p_x << endl; int** p_p_x = &p_x; cout << "value of p_p_x = " << p_p_x << endl; int*** p_p_p_x = &p_p_x; cout << "value of p_p_p_x = " << p_p_p_x << endl; ***p_p_p_x = 15; // Change from *p_x = 15; cout << "value of x = " << x << endl; }
Where are the errors? int main(){ int m; int *pm; *pm = 5; int n; int *pn = &n; pn = 5; }
Where are the errors? int main(){ int m; int *pm; *pm = 5; int n; int *pn = &n; pn = 5; } ERROR! No address in pm //Correction pm = &m; *pm = 5;
Where are the errors? int main(){ int m; int *pm; *pm = 5; int n; int *pn = &n; pn = 5; } ERROR! No address in pm //Correction pm = &m; *pm = 5; ERROR! Missing operator* //Correction *pn = 5;
Error messages For pn = 5; MS VS: “error C2440: '=' : cannot convert from 'int' to 'int *‘. Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast”
Error messages For int *pm; *pm = 5; MSVS: warning C4101: ‘pm' : unreferenced local variable; warning C4700: uninitialized local variable 'pm' used.
Error messages • Executing the program after comment out pn = 5; (thus no compilation error, just warnings).
Pointer and Array • A name of an array holds the address of the first element in the array. • Thus, an array is just a pointer const (cannot be changed). • This definition is different from the usual definition of array. • Pointers and arrays point to elements of the same type.
Example int a[5] = {1,2,3,4,5}; cout << "a[2] = " << a[2] << endl; cout << "a = " << a << endl; cout << "a+2 = " << (a+2) << endl; cout << "a+4 = " << (a+4) << endl; cout << "a+6 = " << (a+6) << endl; Output: a[2] = 3 a = 0012FF50 a+2 = 0012FF58 a+4 = 0012FF60 a+6 = 0012FF68
Example int a[5] = {1,2,3,4,5}; *(a+3) = 20; cout << " a[3] = " << a[3] << endl; Output: a[3] = 20
Example int a[5] = {1,2,3,4,5}; *(a+5) = 40; cout << "*(a+5) = " << *(a+5) << endl; Output: *(a+5) = 40
Pointer Arithmetic • C/C++ allow pointer arithmetic: + and – for pointer and array, ++ and -- for pointer. • If a and p are array and pointer respectively, the following operations are allowed: • p++, p-- • a-1, a+20, p+i*j, p-3*j
Example int a[5] = {1,2,3,4,5}; int *p; p = &a[1]; cout << a[0] << ", " << p[-1]<< ", " << *(p - 1) << endl; cout << a[1] << ", " <<p[0]<< ", " << *(p) << endl; cout << a[2] << ", " << p[1]<< ", " << *(p + 1) << endl; Output: • 1, 1, 1 • 2, 2, 2 • 3, 3, 3
Example int b[5] = {12, 4, 16, 98, 50}; p = b; cout << (*p)++ << endl; // prints 12 cout << *p << endl; // prints 13 cout << *++p << endl; // prints 4 cout << *p << endl; // prints 4 cout << (*p)-- << endl; // prints 4 cout << *p << endl; // prints 3 cout << *--p << endl; // prints 13 cout << *p << endl; // prints 13
Pointer Operations • Operations are adjusted with respect to the location of the element. • Thus, p++ update p to point to the next element, no matter what the type of the element is.
Example double d[5] = {1.0, 3.0, 5.0, 7.0}; cout << "d[2] = " << d[2] << endl; cout << "d = " << (d) << endl; cout << "d+1 = " << (d+1) << endl; cout << "d+2 = " << (d+2) << endl; cout << "d+3 = " << (d+3) << endl; Output: d[2] = 5 d = 0012FEE4 d+1 = 0012FEEC d+2 = 0012FEF4 d+3 = 0012FEFC
Why Pointer Arithmetic • Efficiency!
Example: strcpy char *strcpy (char *dst, const char *src) { int i = 0; for (i = 0; src[i] != '\0'; i++) { dst[i] = src[i]; } dst[i] = '\0'; return dst; }
Example: strcpy using pointers char *strcpy (char *dst, const char *src) { char *retval = dst; while (*dst++ = *src++) ; return retval; }
Pointer Arithmetic • Cryptic (especially using together with ++ and --). • Error-prone. • Avoid using it.
Dynamic Memory Allocation • The proper use of pointer is for dynamic memory allocation. • Data structures of variable sizes can be constructed.
Sizes of data structures • Many data structures require known sizes during their creations. • Examples: arrays • int a[5]; • double d[MAX]; • Student s[20];
Dynamic Sizes • However, many applications require data structures of dynamic sizes. • Examples: • Tasks in an operating system • Number of bidders in an auction • People supporting Obama in Clear Lake
Memory Allocation • The new and new [] operators allocate the necessary memory and return the address.
Example p = new int; *p = 8; cout << "p = " << p << endl; cout << "*p = " << *p << endl; p = new int; // memory leakage. *p = 20; cout << "p = " << p << endl; cout << "*p = " << *p << endl; Output: p = 003354D8 *p = 8 p = 00335580 *p = 20
Example 2: Where is the error? int main(){ int*p,q; p = new int; *p = 8; q = p; cout << "p = " << p << endl; cout << "q = " << q << endl; p = new int; *p = 20; cout << "p = " << p << endl; cout << "q = " << q << endl; cout << "*p = " << *p << endl; cout << "*q= " << *q << endl; }
Example 2 int main(){ int *p, *q; p = new int; *p = 8; q = p; cout << "p = " << p << endl; cout << "q = " << q << endl; p = new int; *p = 20; cout << "p = " << p << endl; cout << "q = " << q << endl; cout << "*p = " << *p << endl; cout << "*q= " << *q << endl; }
Output of Example 2 p = 003354E0 q = 003354E0 p = 00335588 q = 003354E0 *p = 20 *q= 8
Memory Allocation • The memory structure for allocation through new operator is usually called heap. • The C++ Runtime may not have enough memory. Example: p = new int[1000000000]; MSVS: total size of array must not exceed 0x7fffffff bytes
Handling insufficient error int * p = new int [n]; // if it fails an exception bad_alloc is thrown. p = new (nothrow) int [5]; if (p == NULL) { // error allocating memory. };
Memory De-allocation • delete and delete [] are used to de-allocate memory for a single element and an array of elements respectively. • new and delete replaces malloc and free in C. • Example: int * p; … delete p;
Memory Corruption • Unintended pointer operations may cause memory corruption.
Example char *s1; delete s1; cause warning (“uninitialized local variable 's1' used”) and runtime exception.