Pointers

The address of a variable

On our machine storm.cis.fordham.edu, a memory address (and a “pointer” variable that holds a memory address) occupies 64 bits = 8 bytes.
That means it could take up to 64 ÷ 4 = 16 hexadecimal digits to write the address.

  1. address.C, address.txt
    Output the address of a variable in hexadecimal.
    “Ampersand” and “address” begin with the same letter.
    This & is a unary operator (i.e., an operator with only one operand) like the negative sign -i.
    Addition, on the other hand, is a binary operator (i.e., an operator with two operands).

  2. Store the address of a variable into a pointer.
    (Diagram with pointer pointing left.)
    Use the data type size_t for a variable holding the number of elements in an array, or the number of bytes in a block of memory.
    1. pointerint.C, pointerint.txt
      Store the address of an int into a “pointer to an int”.
    2. pointerdouble.C, pointerdouble.txt
      Store the address of a double into a “pointer to a double”.

Dereference a pointer to a stand-alone variable.

Dereferencing a pointer means getting the value of the variable that the pointer points to.
A “stand-alone” variable is one that does not belong to an array or a structure.

  1. This * is a unary operator (i.e., an operator with only one operand) that dereferences the pointer, i.e., gets the value to which the pointer points.
    Multiplication, on the other hand, is a binary operator (i.e., an operator with two operands) that gives you the product of two factors.
    1. dereferenceint.C dereferenceint.txt
    2. dereferencedouble.C, dereferencedouble.txt.
      By default, only six significant digits of a double are output.
      If you want to see more digits, #include <iomanip> and use the i/o manipulator setprecision.

Dereference a pointer to an array element.

  1. If a pointer points to an element in an array, the pointer also gives us access to the values that are neighbors of the element.
    1. neighborint.C, neighborint.txt.
    2. neighbordouble.C, neighbordouble.txt.
  2. Two handy abreviations for use in a program that has a pointer to an array element.
    Let’s say we have
    	int a[] {0, 10, 20, 30, 40, 50, 60, 70, 80, 90};
    
    	const size_t n {size(a)};   //the number of elements in the array
    
    1. In this language, the name of an array all by itself means the address where the array begins.
      So you can write a in place of &a[0].
    2. In this language, if you add an integer to the address where the array begins, you get the address of the element specified by the integer.
      Remember, the name of the array all by itself is the address where the array begins.
      Thus:
      You can write a+1 instead of &a[1].
      You can write a+2 instead of &a[2].

      You can write a+i instead of &a[i].

      You can write a+n instead of &a[n].
    3. Exercise.
      Make the above change to neighborint.C and neighbordouble.C.

A picture of an array of ints in memory

	//Assume that the array starts at memory address 1000.
	//The array contains 10 elements, each occupying 4 bytes on our machine.
	//Therefore the array occupies addresses 1000 to 1039 inclusive.

	int a[] {
		 0,   //Occupies addresses 1000 to 1003
		10,   //Occupies addresses 1004 to 1007
		20,   //Occupies addresses 1008 to 1011
		30,   //Occupies addresses 1012 to 1015
		40,   //Occupies addresses 1016 to 1019
		50,   //Occupies addresses 1029 to 1023
		60,   //Occupies addresses 1024 to 1027
		70,   //Occupies addresses 1028 to 1031
		80,   //Occupies addresses 1032 to 1035
		90    //Occupies addresses 1036 to 1039
	};

Note that the byte at address 1040 is not part of the array.
It is just beyond the end of the array.

Use a pointer in a loop

  1. loop.C, loop.txt
    You can increment (or decrement) a pointer only if it is pointing to an element in an array.
    The increment ++ (or decrement --) will make the pointer point to the next (or to the previous) element in the array. On our machine, the increment adds 4 to to the pointer because what the pointer point to (an int) occupies 4 bytes.
  2. elementaddress.C, elementaddress.txt
    Output the address of each element of an array, in hexadecimal.
    When we increment a pointer to an int (with ++p), we are actually adding 4 to the value of the pointer.
    That’s because each int occupies 4 bytes of memory.
    (The addresses are up in the 140 trillions.)
  3. rocket1.C: overwrite four consecutive array elements. Has to be seen to be believed.
    rocket2.C: The same program, but with an int i instead of a pointer p. The statements
    		p[0] = '.';        //trailing puff of smoke
                    p[1] = '=';
                    p[2] = '=';
                    p[3] = '>';        //the nose cone
    in rocket1.C are simpler than the statements
    		a[i + 0] = '.';        //trailing puff of smoke
                    a[i + 1] = '=';
                    a[i + 2] = '=';
                    a[i + 3] = '>';        //the nose cone
    
    in rocket2.C.
  4. movingaverage.C, movingaverage.txt. compute the sum of five consecutive array elements.
    The expression
    p[-2] + p[-1] + p[0] + p[1] + p[2]
    
    in movingaverage.C is simpler than the expression
    a[i-2] + a[i-1] + a[i] + a[i+1] + a[i+2]
    
  5. Use a pointer to access a pair of consecutive elements of an array.
    1. bubble1.C, bubble1.txt. Uses subscripts i, j.
    2. bubble2.C, bubble2.txt. Uses pointers p, q.
    The statement
    if (q[0] > q[1]) {
    
    in bubble2.C is simpler than the statement
    if (a[j] > a[j + 1]) {
    
    in bubble1.C.

Dereference a pointer to a structure.

  1. We saw an array of structures here:
    struct.C, struct.txt.
    Use the unary * operator to dereference a “pointer to a structure”.
    Then use the binary . operator get the value of each field of the structure.
    See the asterisk in level 3 and the dot in level 2 of the table of operator precedences and associativities.
    struct.C, struct.txt

Three ways to pass an argument to a function

  1. pass.C, pass.txt.
    Three good ways to pass an argument to a function.
    (The second argument, readwriteref, is bad!)
    1. The function f receives a copy of the variable i, and can change the value of the copy.
      (The name of the copy is cop.)
      But changing the value of the copy has no effect on the value of the i up in main.
    2. readonlyref is just another name for the variable t.
      No copy of t is created.
      Because of the keyword const, the function f cannot use readonlyref to change the value of t.
    3. The function receives the address of the variable j, and can use this address (dereferenced with a *) to install a new value into j.
    The statement that calls the function (f(i, s, t, &j);) makes it obvious that the function can change the value of j.

Two ways to pass an array to a function

  1. array.C, array.txt.
    Pass the address of the start and end (actually, just beyond the end) of an array to a function.

Pass a structure to a function

  1. passstruct.C, passstruct.txt.
    Pass the address of a structure to a function.
    We had to tell the computer what a month is before we could tell the computer what f is.
    Believe it or not, passing the address of a structure to a function will be the jumping-off point into the world of Object-Oriented Programming!

Two ways to make a pointer const

You can insert the keyword const into a declaration in two places:

  1. at the start of the declaration
  2. immediately after an asterisk in the declaratation
	int i {10};
	int j {20};
	int *p {&i};   //p points to i.

The following diagram shows two regions of memory, the pointer on the right and the pointed-to variable on the left.

  1. const.C. Not allowed to change the value of a const variable. It always holds the same value.
    If you uncomment the ++j in line 18, the c++ compiler will say
    const.C:18:11: error: increment of read-only variable ā€˜j’
    
  2. constptr.C. Not allowed to change the value of a const pointer. It always points to the same place.
  3. readonly.C. A read-ony pointer is a needle that can’t scratch the record.
  4. both.C. A pointer that is const in both ways.