====== Pointer Variable Declarations and Initialization ====== * Pointer variables contain **memory addresses** as their values. Normally, a variable directly contains a specific value. However, a pointer contains the memory address of a variable that, in turn, contains a specific value. In this sense, a variable name **directly references a value**, and a pointer **indirectly references a value**. Referencing a value through a pointer is often called **indirection**. * Pointers, like any other variables, must be declared before they can be used. For example, the declaration int *countPtr, count; declares the variable countPtr to be of type int * (i.e., a pointer to an int value) and is read, **"countPtr is a pointer to int"** or **"countPtr points to an object of type int."** Also, variable count in the preceding declaration is declared to be an int, not a pointer to an int. The * in the declaration applies only to countPtr. **Each variable being declared as a pointer must be preceded by an asterisk (*).** For example, the declaration double *xPtr, *yPtr; indicates that both xPtr and yPtr are pointers to double values. *Pointers should be initialized either when they are declared or in an assignment. A pointer may be initialized to 0, NULL or an address. A pointer with the value 0 or NULL points to nothing and is known as a null pointer. Symbolic constant NULL is defined in header file (and in several other standard library header files) to represent the value 0. Initializing a pointer to NULL is equivalent to initializing a pointer to 0, but in C++, 0 is used by convention. When 0 is assigned, it is converted to a pointer of the appropriate type. The value 0 is the only integer value that can be assigned directly to a pointer variable without casting the integer to a pointer type first. ====== Pointer Operators ====== * The address operator (&) is a unary operator that returns the memory address of its operand. For example, assuming the declarations int y = 5; // declare variable y int *yPtr; // declare pointer variable yPtr the statement yPtr = &y; // assign address of y to yPtr assigns the address of the variable y to pointer variable yPtr. Then variable yPtr is said to "point to" y. Now, yPtr indirectly references variable y's value. Note that the use of the & in the preceding assignment statement is not the same as the use of the & in a reference variable declaration, which is always preceded by a data-type name. * The * operator, commonly referred to as the indirection operator or dereferencing operator, returns a synonym (i.e., an alias or a nickname) for the object to which its pointer operand points. For example, the statement cout << *yPtr << endl; prints the value of variable y, namely, 5, just as the statement cout << y << endl; would. Using * in this manner is called dereferencing a pointer. Note that a dereferenced pointer may also be used on the left side of an assignment statement, as in *yPtr = 9; which would assign 9 to y. The dereferenced pointer may also be used to receive an input value as in cin >> *yPtr; which places the input value in y. ===== Pointer operators & and * ===== 1 // 2 // Using the & and * operators. 3 #include 4 using std::cout; 5 using std::endl; 6 7 int main() 8 { 9 int a; // a is an integer 10 int *aPtr; // aPtr is an int * -- pointer to an integer 11 12 a = 7; // assigned 7 to a 13 aPtr = &a; // assign the address of a to aPtr 14 15 cout << "The address of a is " << &a 16 << "\nThe value of aPtr is " << aPtr; 17 cout << "\n\nThe value of a is " << a 18 << "\nThe value of *aPtr is " << *aPtr; 19 cout << "\n\nShowing that * and & are inverses of " 20 << "each other.\n&*aPtr = " << &*aPtr 21 << "\n*&aPtr = " << *&aPtr << endl; 22 return 0; // indicates successful termination 23 } // end main ====== Passing Arguments to Functions by Reference with Pointers ====== * There are three ways in C++ to pass arguments to a function; **pass-by-value, pass-by-reference with reference arguments and pass-by-reference with pointer arguments.** * Pointers, like references, also can be used to modify one or more variables in the caller or to pass pointers to large data objects to avoid the overhead of passing the objects by value. * In C++, programmers can use pointers and the indirection operator (*) to accomplish pass-by-reference (exactly as pass-by-reference is done in C programs, because C does not have references). When calling a function with an argument that should be modified, the address of the argument is passed. This is normally accomplished by applying the address operator (&) to the name of the variable whose value will be modified. * Arrays are not passed using operator &, because the name of the array is the starting location in memory of the array (i.e., an array name is already a pointer). The name of an array, arrayName, is equivalent to &arrayName[ 0 ]. When the address of a variable is passed to a function, the indirection operator (*) can be used in the function to form a synonym for the name of the variable. this in turn can be used to modify the value of the variable at that location in the caller's memory. ===== Pass-by-value used to cube a variable's value ===== 1 2 // Cube a variable using pass-by-value. 3 #include 4 using std::cout; 5 using std::endl; 6 7 int cubeByValue( int ); // prototype 8 9 int main() 10 { 11 int number = 5; 12 13 cout << "The original value of number is " << number; 14 15 number = cubeByValue( number ); // pass number by value to cubeByValue 16 cout << "\nThe new value of number is " << number << endl; 17 return 0; // indicates successful termination 18 } // end main 19 20 // calculate and return cube of integer argument 21 int cubeByValue( int n ) 22 { 23 return n * n * n; // cube local variable n and return result 24 } // end function cubeByValue * Above example passes variable number by value to function cubeByValue (line 15). Function cubeByValue (lines 21-24) cubes its argument and passes the new value back to main using a return statement (line 23). The new value is assigned to number (line 15) in main. Note that the calling function has the opportunity to examine the result of the function call before modifying variable number's value. For example, in this program, we could have stored the result of cubeByValue in another variable, examined its value and assigned the result to number only after determining that the returned value was reasonable. ===== Pass-by-reference with a pointer argument used to cube a variable's value ===== 1 // Fig. 8.7: fig08_07.cpp 2 // Cube a variable using pass-by-reference with a pointer argument. 3 #include 4 using std::cout; 5 using std::endl; 6 7 void cubeByReference( int * ); // prototype 8 9 int main() 10 { 11 int number = 5; 12 13 cout << "The original value of number is " << number; 14 15 cubeByReference( &number ); // pass number address to cubeByReference 16 17 cout << "\nThe new value of number is " << number << endl; 18 return 0; // indicates successful termination 19 } // end main 20 21 // calculate cube of *nPtr; modifies variable number in main 22 void cubeByReference( int *nPtr ) 23 { 24 *nPtr = *nPtr * *nPtr * *nPtr; // cube *nPtr 25 } // end function cubeByReference * Above passes the variable number to function cubeByReference using pass-by-reference with a pointer argument (line 15)the address of number is passed to the function. Function cubeByReference (lines 22-25) specifies parameter nPtr (a pointer to int) to receive its argument. The function dereferences the pointer and cubes the value to which nPtr points (line 24). This directly changes the value of number in main. ===== Converting a string to uppercase ===== 1 // Fig. 8.10: fig08_10.cpp 2 // Converting lowercase letters to uppercase letters 3 // using a non-constant pointer to non-constant data. 4 #include 5 using std::cout; 6 using std::endl; 7 8 #include // prototypes for islower and toupper 9 using std::islower; 10 using std::toupper; 11 12 void convertToUppercase( char * ); 13 14 int main() 15 { 16 char phrase[] = "characters and $32.98"; 17 18 cout << "The phrase before conversion is: " << phrase; 19 convertToUppercase( phrase ); 20 cout << "\nThe phrase after conversion is: " << phrase << endl; 21 return 0; // indicates successful termination 22 } // end main 23 24 // convert string to uppercase letters 25 void convertToUppercase( char *sPtr ) 26 { 27 while ( *sPtr != '\0' ) // loop while current character is not '\0' 28 { 29 if ( islower( *sPtr ) ) // if character is lowercase, 30 *sPtr = toupper( *sPtr ); // convert to uppercase 31 32 sPtr++; // move sPtr to next character in string 33 } // end while 34 } // end function convertToUppercase * Function convertToUppercase (lines 25-34) declares parameter sPtr (line 25) to be a nonconstant pointer to nonconstant data (again, const is not used). The function processes one character at a time from the null-terminated string stored in character array phrase (lines 2733). Keep in mind that a character array's name is really equivalent to a pointer to the first character of the array, so passing phrase as an argument to convertToUppercase is possible. Function islower (line 29) takes a character argument and returns true if the character is a lowercase letter and false otherwise. Characters in the range 'a' through 'z' are converted to their corresponding uppercase letters by function toupper (line 30); others remain unchangedfunction toupper takes one character as an argument. If the character is a lowercase letter, the corresponding uppercase letter is returned; otherwise, the original character is returned. Function toupper and function islower are part of the character-handling library . After processing one character, line 32 increments sPtr by 1 (this would not be possible if sPtr were declared const). When operator ++ is applied to a pointer that points to an array, the memory address stored in the pointer is modified to point to the next element of the array (in this case, the next character in the string). Adding one to a pointer is one valid operation in **pointer arithmetic**.