Broad Network


Comparing C++ Pointer and Reference

Some Features of C++ Entities – Part 10

Forward: In this part of the series, I compare C++ pointers and references.

By: Chrysanthus Date Published: 25 Sep 2012

Introduction

This is part 10 of my series, Some Features of C++ Entities. In this part of the series, I compare C++ pointers and references. In this volume, in the series, C++ Taking the Bull by the Horns, I have a tutorial titled, C++ Pointers. That tutorial is a comprehensive article on C++ pointers. If you have forgotten about pointers, then read the tutorial first before you read this article. Whatever is the case, the tutorials of this series should be read in the order given. You also should have read the series before this series (see link on C++ Course below).

Nature
A pointer is declared using * while a reference is declared using &. When talking about pointers, two objects (regions in memory) are concerned: you have the pointer object and the pointed object. The pointer object has the address of the pointed object. The pointed object has the value. When dealing with reference, you have two different identifiers (names). Each of the identifiers has the same address, identifying the same region in memory for the same value.

Declaration with Initialization
A pointer is declared with initialization as in:

    int *pointer = &identifier;

Here, pointer is the pointer object identifier, "identifier" is some predeclared identifier, and the expression, &identifier is the address of the identifier. You can call the expression, &identifier a reference. In this statement, the pointed object has the address given by the expression, &identifier. * is called the dereference operator, used to declare a pointer.

A reference is declared with initialization as in:

    int &herInt = hisInt;

Here, herInt is a new identifier, while hisInt is some pre-declared identifier. This statement makes the two identifiers to have the same address. The expression, &herInt is the reference; it is also the address. & is the reference operator, used to declare a reference. You can call herInt the reference identifier.

Useful Statements without Initialization
The following code segment shows how a pointer can be declared and used without the initialization statement and without the reference operator:

            int *pointer;
             *pointer = 5;
             cout << *pointer << '\n';

The first statement declares the pointer using the dereference operator. In the first statement there is no indication of the pointed object; you have only the pointer object identified by, pointer. The second statement uses the dereference operator and the pointer object identifier to create an anonynous (no name - not identified) pointed object and place the value, 5 in it.

As you can see, the dereference operator in the two statements have two different meanings. In the first statement which is the declaration statement, it is indicating that the identifier, pointer is for the pointer object. In the second statement, which is not a declaration statement and without the preceding specifier, int, the dereference operator means the value of the pointed object, whose addess is in the pointer object. In the third statement, the dereference operator also means the value of the pointed object whose addess is in the pointer object. It uses the pointer object identifier and not the pointed object identifier for this purpose.

For the reference, you cannot have declaration without initialization. However, in a workable group of statements, you can have the reference without the dereference operator. When you need the value of the referenced object, you use either the reference identifier or the pre-declared identifier. The following code segment illustrates this:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << hisInt << '\n';
        cout << herInt << '\n';

Here the first statement has the pre-declared identifier. The second statement establishes the reference, "&herInt" with the new identifier, herInt and the pre-declared identifier, hisInt. The statement automatically makes both identifiers have the same address. The last two statements display the value of the same object (region in memory) identified by the two identifiers. Neither of the two statements uses the & operator. The first of the last two statements uses the pre-declared identifier and the second one uses the reference identifier. Note that the assignement operator in the second statement of the whole code, behaves in an overloaded fashion.

Code Segments with * and &
The classical way to use a pointer is as follows:

            int pointed;
            int *pointer = &pointed;
            *pointer = 5;
            cout << *pointer;

The first statement declares the pointed object (identifier) without assigning any value to it. The second statement declares the pointer using the address of the pointed object. The third statement assignes a value for the pointed object.

The * in the second statement behaves in a different way to the * in the third statement. In the second statement, * works with the identifier, "pointer", in the declaration statement with int, to indicate that "pointer" is the identifier of the pointed object. In the third and fourth statements, * works with the identifier, "pointer" to access the value of the pointed object.

The above code segment can alternatively be written as follows:

        int pointed;
        int *pointer;
        pointer = &pointed;
        *pointer = 5;
        cout << *pointer;

Here, in the third statement, the address of the pointed object is assigned to the identifier (object) of the pointer object.

In C++, the reference with & was first invented before the pointer with *. So, in the classical use of the pointer with *, the & for the reference is involved. In the classical use of the reference, * and the pointer are both not involved. The classical use of the reference is as follows:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << herInt << '\n';

In the code, there is an address for the stored object value and the value can be obtained from the reference identifier. As you can see, there is no need for the * operator and its pointer. Over time it was seen that this coding is limited for many situations, so the pointer and * was invented (added to C++).

You can however force a * and pointer into the code, as in the following segment:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << *(&herInt) << '\n';

Here, in the third statement, the pointer is "&herInt" in parentheses. * preceding it and in association with it, accesses the value of the object whose address is &herInt pointed to by (&herInt). If you omit the parentheses in this code segment, the code will still work. In the code segment, (&herInt) is the forced pointer.

Parameter of a Function
Consider the following program that works for a pointer as function parameter:

#include <iostream>
using namespace std;

    int aFn(int *no)
        {
            cout << *no; cout << "\n";

            int anInt = 77;
            no = &anInt;
            
            return *no;
        }

    int main()
        {
            int myInt = 88;
            int hisRet = aFn(&myInt);
    
            cout << hisRet;
    
            return 0;
        }

In the function, the parameter is:

    int *no

This is a declaration and so the association of * and the identifier, no, mean that no is the identifier of a pointer. As soon as the function, aFn() starts executing, the following initialization statement is established:

    int *no = &myInt;

This is similar to the pointer initialization statement given somewhere above. &myInt is the argument of the corresponding function call in main. So, if the parameter of a function is a pointer, send an address as argument. For the parameter of the above function, it does not matter, whether * is closer to int or no.

Consider the following program that works for a reference as function parameter:

#include <iostream>
using namespace std;

    int aFn(int &no)
        {
            cout << no; cout << "\n";

            no = 77;
            
        }

    int main()
        {
            int theInt = 88;
            aFn(theInt);
    
            cout << theInt;
    
            return 0;
        }

In the function, the parameter is:

    int &no

This is a declaration (actually left half of a declaration) and so the association of & and the identifier, no, mean that no is the identifier of a reference. As soon as the function, aFn() starts executing, the following initialization statement is established:

    int &no = theInt;

This is similar to the reference initialization statement given somewhere above. theInt is the argument of the corresponding function call in main. So, if the parameter of a function is a reference, send an ordinary identifier as argument. For the parameter of the above function, it does not matter, whether & is closer to int or no.

Function Return Type
Consider the following program for a function pointer return type that works:

#include <iostream>
using namespace std;

    int *theFn()
        {
            int pointed = 6;
            int *pointer = &pointed;
            
            return pointer;
        }

    int main()
        {
            int *receiver = theFn();
    
            cout << *receiver;
    
         return 0;
        }

We see from the above program that if the return type is a pointer, indicated by *, you have to return a pointer identifier. It is as if you are creating a pointer initialization statement. For the above function definition, it does not matter whether the * is closer to int or theFn(). It is received in main by a pointer identifier, either in a pointer declaration or in a pointer assignment.

Consider the following program for a reference return type that works:

#include <iostream>
using namespace std;

    int &aFn()
        {
          int hisInt;
          int &herInt = hisInt;
          hisInt = 5;
          return herInt;
        }

    int main()
        {
            int ident = aFn();
            cout << ident;  

            return 0;
        }

We see from the above program that if the return type is a reference, indicated by &, you have to return a reference identifier. It is as if you are creating a reference initialization statement. For the above function definition, it does not matter whether the & is closer to int or aFn(). Note that here in main, the return value can also be received by a referece (left half) declaration, as in

            int &ident = aFn();

In the code it is received by an ordinary identifier.

That is it, for comparison of pointer and reference in C++. We stop here and continue in the next part of the series.

Chrys

Related Courses

C++ Course
Relational Database and Sybase
Windows User Interface
Computer Programmer – A Jack of all Trade – Poem
NEXT

Comments

Become the Writer's Fan
Send the Writer a Message