Files
CSCI-1200/lectures/04_pointers/README.md
2023-09-11 21:22:50 -04:00

6.8 KiB
Raw Blame History

Lecture 4 --- Pointers, Arrays, & Pointer Arithmetic

  • Pointers store memory addresses.
  • They can be used to access the values stored at their stored memory address.
  • They can be incremented, decremented, added, and subtracted.
  • Dynamic memory is accessed through pointers.
  • Pointers are also the primitive mechanism underlying vector iterators, which we have used with std::sort and will use more extensively throughout the semester.

4.1 Pointer Example

  • Consider the following code segment:
float x = 15.5;
float *p; /* equiv: float* p; or float * p; */
p = &x;
*p = 72;
if ( x > 20 )
cout << "Bigger\n";
else
cout << "Smaller\n";

The output is Bigger because x == 72.0. Whats going on?

alt text

4.2 Pointer Variables and Memory Access

  • x is an ordinary float, but p is a pointer that can hold the memory address of a float variable. The difference is explained in the picture above.
  • Every variable is attached to a location in memory. This is where the value of that variable is stored. Hence, we draw a picture with the variable name next to a box that represents the memory location.
  • Each memory location also has an address, which is itself just an index into the giant array that is the computer memory.
  • The value stored in a pointer variable is an address in memory. The statement p = &x; takes the address of xs memory location and stores it (the address) in the memory location associated with p.
  • Since the value of this address is much less important than the fact that the address is xs memory location, we depict the address with an arrow.
  • The statement: *p = 72; causes the computer to get the memory location stored at p, then go to that memory location, and store 72 there. This writes the 72 in xs location.

Note: *p is an l-value in the above expression.

4.3 Defining Pointer Variables

  • In the example below, p, s and t are all pointer variables (pointers, for short), but q is NOT. You need the * before each variable name.
int * p, q;
float *s, *t;
  • There is no initialization of pointer variables in this two-line sequence, so the statement below is dangerous, and may cause your program to crash! (It wont crash if the uninitialized value happens to be a legal address.)
*p = 15;

4.4 Operations on Pointers

  • The unary (single argument/operand) operator * in the expression *p is the “dereferencing operator”. It means “follow the pointer” *p can be either an l-value or an r-value, depending on which side of the = it appears on.
  • The unary operator & in the expression &x means “take the memory address of.”
  • Pointers can be assigned. This just copies memory addresses as though they were values (which they are). Lets work through the example below (and draw a picture!). What are the values of x and y at the end?
float x=5, y=9;
float *p = &x, *q = &y;
*p = 17.0;
*q = *p;
q = p;
*q = 13.0;
  • play this animation.

  • Assignments of integers or floats to pointers and assignments mixing pointers of different types are illegal. Continuing with the above example:

int *r;
r = q; // Illegal: different pointer types;
p = 35.1; // Illegal: float assigned to a pointer
  • Comparisons between pointers of the form if ( p == q ) or if ( p != q ) are legal and very useful! Less than and greater than comparisons are also allowed. These are useful only when the pointers are to locations within an array.

4.5 Exercise

  • Draw a picture for the following code sequence. What is the output to the screen?
int x = 10, y = 15;
int *a = &x;
cout << x << " " << y << endl;
int *b = &y;
*a = x * *b;
cout << x << " " << y << endl;
int *c = b;
*c = 25;
cout << x << " " << y << endl;

4.6 Null Pointers

  • Like the int type, pointers are not default initialized. We should assume its a garbage value, leftover from the previous user of that memory.
  • Pointers that dont (yet) point anywhere useful are often explicitly assigned to NULL. NULL is equal to the integer 0, which is a legal pointer value (you can store NULL in a pointer variable). But NULL is not a valid memory location you are allowed to read or write. If you try to dereference or follow a NULL pointer, your program will immediately crash. You may see a segmentation fault, a bus error, or something about a null pointer dereference. NOTE: In C++11, we are encouraged to switch to use nullptr instead of NULL or 0, to avoid some subtle situations where NULL is incorrectly seen as an int type instead of a pointer. For this course we will assume NULL and nullptr are equivalent. We indicate a NULL or nullptr value in diagrams with a slash through the memory location box.
    • Comparing a pointer to NULL is very useful. It can be used to indicate whether or not a pointer variable is pointing at a useable memory location. For example,
if ( p != NULL )
cout << *p << endl.

tests to see if p is pointing somewhere that appears to be useful before accessing and printing the value stored at that location.

  • But dont make the mistake of assuming pointers are automatically initialized to NULL

4.7 Arrays

  • Heres a quick example to remind you about how to use an array:
const int n = 10;
double a[n];
int i;
for ( i=0; i<n; ++i )
a[i] = sqrt( double(i) );
  • Remember: the size of array a is fixed at compile time. STL vectors act like arrays, but they can grow and shrink dynamically in response to the demands of the application.

  • play this animation.

4.8 Sorting an Array

  • Arrays may be sorted using std::sort, just like vectors. Pointers are used in place of iterators. For example, if a is an array of doubles and there are n values in the array, then heres how to sort the values in the array into increasing order:
std::sort( a, a+n );

4.9 Exercises