User Tools

Site Tools


cplusplus:pointers_2

Pointers 2

Pointers and comparisons, functions, and qualifiers.1)

Comparing pointers

Relational operators can be used with pointer variables. But be aware of the difference between comparing the value of the pointer (an address) and comparing the contents of that address.

double x = 2.2;
double y = 4.8;
double *aPtr = &x;
double *bPtr = &y;
 
if (aPtr == bPtr) ...   // compare addresses
if (*aPtr == *bPtr) ... // compare contents of addresses, i.e. same as
if (x == y) ...

Pointers as function parameters

Pointers can be used as function parameters. Arguments (i.e., actual parameters) can be anything that can be assigned to a pointer, that is, addresses or pointers.

function-with-pointer.cpp
/** Demonstrates how to pass pointers to functions. */
#include <iostream>
using namespace std;
 
void printPtr(int *);   // prototype
 
int main()
{
    int number = 5;
    int *myPtr = &number;
 
    printPtr(myPtr);     // pass in a pointer
    printPtr(&number);   // pass in an address
 
    return 0;
}
 
/**
 * Simple function showing how to pass pointers to functions.
 * Print the value of nPtr and the value of dereferenced nPtr.
 */
void printPtr(int *nPtr)
{
    cout << "The value of the pointer is " << nPtr << endl
         << "The value of the thing pointed to by the pointer is "<< *nPtr << endl;
}

Calling functions by reference

Pointers can be used to implement call-by-reference in functions. The * operator is used to alias a variable inside of function.

void doubleIt(int *number)
{
    *number = 2 * (*number);
}

In the function above, *number is used as an alias for the variable passed in. Strictly speaking, the passing mechanism is call-by-value because the argument that is passed into the function (an address) is copied to the formal pointer parameter number. However, dereferencing number acts as an alias to whatever is passed in.

cube-by-reference.cpp
/** Cube a variable using call-by-reference with a pointer. */
#include <iostream>
using namespace std;
void cubeByReference(int *);   // prototype
 
int main()
{
    int number = 5;
    cout << "The original value of number is " << number << endl;
    cubeByReference(&number);
    cout << "The new value of number is " << number << endl;
    return 0;
}
 
/** Cube the integer pointed to by nPtr. */
void cubeByReference(int *nPtr)
{
    *nPtr = (*nPtr) * (*nPtr) * (*nPtr); // parenthesis for readability
}

I feel pointers are much better than reference parameters for implementing call by reference because the syntax in the function invocation (e.g., cubeByReference(&number)) makes it clear that a pointer is involved — which is good indication that call by reference is being used.

The const qualifier and pointers

You are already familiar with C++'s const qualifier when used with regular variables. To review:

  • const variables cannot be changed (i.e., they become constants).
  • const should be used on a function parameter when the function does not need to change that parameter's value.
  • Attempting to change a const variable or parameter is a syntax error (which should be caught by the compiler).

Applying the const qualifier to pointers is a little more complicated. What is constant? The pointer value or the value of the thing pointed to?

The answer is either or both.

Constant pointers

A constant pointer is a pointer whose value cannot change; that is, constant pointers store a memory location that cannot be changed. Constant pointers must be initialized when declared, and once initialized cannot be reassigned. In other words, a constant pointer always points to the same chunk of memory.

To declare a constant pointer, use the const keyword between the * and the name of the pointer:

const-ptr-demo.cpp
/** Attempting to modify a constant pointer to non-constant data. */
#include <iostream>
using namespace std;
int main()
{
    int x = 2, y = 5;
    int * const myPtr = &x;  // constant pointer to a (non-constant) int
                             // The data pointed to by myPtr can be 
                             // modified through myPtr, but myPtr must
                             // always point to the same memory location.
 
    *myPtr = 99;   // change value stored in x to 99
    myPtr = &y;    // syntax error!!
 
    cout << *myPtr << endl;
 
    return 0;
}

Pointer to constant data

You can also create a pointer that is itself not constant (i.e., it can be reassigned or can change “what is being pointed to”) but that cannot change the value of “what is being pointed to.” This is a pointer to constant data or simply pointer to constant.

To create a pointer to constant data, use the const keyword to qualify the type being pointed to.

int x = 2, y = 5;
const int *myPtr = &x;  // non-constant pointer to a constant int
 
*myPtr = 99;   // syntax error!
myPtr = &y;    // no problem, myPtr now points to y

One way to remember this is const modifies the thing immediately following it.”

In the case of:

int *const myPtr = &x;

const modifies myPtr, meaning the value of myPtr is constant.

In the case of:

const int *myPtr = &x;

const modifies int, meaning the value of the int is constant.

Constant pointer to constant data

Combining the above, you can create a pointer that can change neither “what it is pointing to” nor the value of “what it is pointing to.”

int x = 2, y = 5;
const int *const myPtr = &x;// constant pointer to a constant int
 
*myPtr = 99;   // syntax error!
myPtr = &y;    // syntax error!
1)
Portions loosely adapted from: Deitel, Harvey M., and Paul J. Deitel. “Pointers and Strings.” In C++: How to Program. 3 ed. Upper Saddle River, NJ: Prentice Hall, 2001. 304-388.
cplusplus/pointers_2.txt · Last modified: 2019/03/11 19:53 by mithat