Broad Network


Reference in C++

C++ Just After the Basics - Part 9

Forward: In this article I explain how in your work, emphasis can be laid on the reference operator instead of on the dereference operator.

By: Chrysanthus Date Published: 22 Aug 2012

Introduction

I wrote an article once titled, C++ Pointers. That article is part 5 of a series titled, C++ Taking the Bull by the Horns. To reach that article you can type the title, C++ Pointers, and my name, Chrys in the Search box of this page and click Search. If you do not have basic knowledge in C++, then read in this blog the series whose first part is titled, “Getting Started with C++”. To reach the series, type, Getting Started with C++, in the Search Box of this page and click Search. In the article, “C++ Pointers” of the series, in order to explain pointers, I had to give the meaning of Reference. The reference is got through the reference operator. In that article, the emphasis was not on reference. In this article, the emphasis is on reference.

What you learned in that article is enough to do big things in C++. However, as a programmer you will have to maintain (or modify) programs written by others. It is possible to work with pointers where the emphasis is on references; you may find that in some code tomorrow. The reference and dereference operators are dealing with the same thing (see below).

In this article I explain how in your work, emphasis can be laid on the reference operator instead of the dereference operator and its pointers. I begin the explanation by looking at the main points in the article I wrote on C++ Pointers. That article gives you today’s approach to what the dereference and reference operations are doing. However, do not be surprise to come across a C++ program tomorrow, where emphasis is on the reference operator (&) and not the dereference operator (*).

Note: If you cannot see the code or if you think anything is missing (broken link, image absent), just contact me at forchatrans@yahoo.com. That is, contact me for the slightest problem you have about what you are reading.

Pointers
When talking about pointers you are talking about two objects: the pointer object and the pointed object. The pointed object is the object whose content is the useful value. The content of the pointer object is the address, called the reference, of the pointed object. Consider the following code segment:

    int hisInt;
    int *myInt;

    myInt = &hisInt;

In the first statement, an empty object of type int is defined. In the next statement, an empty pointer (object) that will point to an object that is of type int (an object that will hold an int or is holding an int) is declared. In the third statement, the address of the int object of the first statement is assigned to the pointer. In order to obtain the address you have to proceed the object name with the reference operator, &. The above three statements can be reduced to two statements as in the following code:

    int hisInt;
    int *myInt = &hisInt;

In the previous code segment, the address is assigned to the pointer in the third statement. In this code segment, the address is assigned during initialization of the pointer. In the initialization statement, the dereference operator (*), has a different use; it is not dereferencing the word that follows; it indicates that the word that follows is a pointer. In the assignment statement without the dereference operator, in the previous code, the pointer is the identifier of the object (region in memory) that holds the address of the pointed object. In the two code segments, the pointer object identifier is, myInt, and the pointed object identifier is, hisInt.

Again, there are two objects of interest, the pointer object and the pointed object. In order to access the value (content) of the pointed object, you can either use the identifier for the pointed object itself or you can use the pointer and the dereference operator. The dereference operator is, *. In the declaration or initialization of a pointer, the dereference operator does not serve its formal role. The formal role of the dereference operator is to assign or return the value of the object pointed to by the pointer. In this case the dereference operator is used with the pointer (identifier of the pointer object). After either of the above two code segments, either of the following two expressions will access the value of the pointed object:

        hisInt = 5;

        *myInt = 5;

Read and try the following code:

#include <iostream>
using namespace std;

int main()
    {
        int hisInt;
        int *myInt = &hisInt;

        hisInt = 5;
        cout << *myInt;

        return 0;
    }

You now know the basic meaning of pointers, which involves references and the reference operator. It also involves the dereference operator. I expected you to have known what I have said about pointers before reading this article; that above, was revision. Most of the rest of this article deals with the topic, reference, in question.

References
So far as the meaning of reference is concerned, you do not really need to know much more than what I have given you above. A reference is the memory address of an object; to obtain a reference precede the identifier of the object with the reference operator, &. From this last sentence you can see that the problem with reference is to know how to use it; and not just to know what it means. How do you use it without the dereference operator in the declaration and assignment of fundamental objects? How do you use it as a parameter of a function? How do you use it for the return type specifier of a function? I answer these questions below.

Note one thing in the above code segments: the object exists first before we can precede its identifier in anther statement during the creation of the reference. We shall exploit this feature for the rest of this article.

Declaring and Assigning Fundamental Objects
Consider the following code segment:

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

The first statement declares an int object. You have to learn how to interpret the second statement. Here the assignment operator behaves in a different way. It does not behave in the normal way. The second statement is interpreted like this: &herInt (including the &) becomes the address of the object identified by, hisInt. The address of the object hisInt will actually be stored in some region in memory; you will be able to access it with &herInt (including the &). Note the position of & and the identifier of the actual object in the second statement. Also note that the name associated with the reference is introduced in this second statement. In this second statement, note that the & operator is in the left operand and not the right.

Let us look at the third statement; &herInt as an entity, is a pointer. A pointer is an address to an object in memory. In the preceding section we saw a formal interpretation of a pointer. If you read the section again you will realize that something like, &herInt is also a pointer. Now that &herInt is a pointer, you can dereference it to have the value pointed to by the entity, &herInt, value of which is 5 in this case. This is what is achieved in the third statement. You begin with the dereference operator, *, which is followed by the entity, &herInt, in parentheses. In this case the parentheses are optional. The third statement sends the value of hisInt to the output.

You create a reference by initialization as in the second statement in the above code segment. Note: You cannot separate the declaration of the reference and the assignment of the object pointed to, into two different statements, as you do with pointers. Read and try the following code that illustrates all that:

#include <iostream>
using namespace std;

int main()
    {
         int hisInt;
         int &herInt = hisInt;
         hisInt = 5;
         cout << *&herInt;

         return 0;
    }

Note that in the above code the object pointed to was declared first before the initialization of the reference.

Reference as Function Parameter
The parameter of a function can be a reference (address of an object). The following code illustrates this:

#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;
        }

As the program starts, 88 is assigned to the object whose identifier is theInt, in main. The next statement in the main function calls the function, aFn, passing the identifier of the object whose value is 88 as argument. The parameter of the called function is “int &no”. Immediately the called function starts executing, the parameter address becomes equivalent to &theInt, which is the address of the object declared in the first statement of the main function. So immediately the execution of the called function starts, &no and &theInt are the same address to one object; that is, no and theInt are identifying the same object.

The first statement in the called function displays the value of no which is the same as the value of theInt. The second statement in the called function assigns a new value to no, automatically assigning the new value to theInt, because both identifiers identify the same object. The called function does not have a return statement even though its definition begins with a return type; that is acceptable; that is not part of the topic here; it is for those who may be inquisitive.

Back in the main function: The called function is called by the second statement in the main function. The called function executes before the next (third) statement in the main function is executed. We did not assign any return value of the called function to any object (identifier) in the main function. We could not do this because the called function did not return anything (had no return statement; not part of this topic though).

The third statement in the main function displays the value of theInt, which is the same value as that for no in the called function.

Note, when passing by reference, the parameter (in called function) is the address of an object (identifier) but the argument (in calling function) is an identifier and not the address of the object (identifier).

Reference as Function Returned Type Specifier
Before we look at reference as function returned type specifier, let us look at pointer as function returned type specifier, so that we can make the contrast. Reference and pointer are dealing with the same idea. A reference e.g. &theInt is an address to an object in memory. A pointer is an object that holds such an address. The pointer identifier can be used in place of the address (&theInt). In the following code, the function outside main has a pointer return type specifier. Read the code and try it.

#include <iostream>
using namespace std;

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

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

For the function, theFn(), the return type is a pointer. The asterisk is used next to the name of the function just after the type of the returned pointed object, int, at the beginning of the declaration of the function. Note the position of the asterisk at the beginning of the declaration of this function. The return statement in the function returns a pointer (address of an object). So we have a pointer function return type and we return a pointer.

So, to return a pointer, you need to put an asterisk in front of the name of the function declaration. The return type (e.g. int) should be the same as the object type the pointer is pointing to. This object type also has to be the return type specifier of the function declaration.


The following code does the opposite.

#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;
        }

In this code we have a reference function returned type and we return the value of the object pointed to by a reference. Note the position of the & operator in the function declaration. The return type of the function has to be of the same type as the value returned. Note that the above function can be written without the & or * operator, but more memory may be used.

Summary of the use of &
You can find & in a declaration like:

          int &herInt = hisInt;

You can also find it as a return type, like in:

    int &aFn();

You can also find it in a function parameter list like in:

    int theFn(int &no)

So, when you have, &identifier, send an ordinary identifier to it. In the first case here, hisInt has been sent as initialization value to, &herInt. For function interface, such as “int &aFn()” the return type above is, “*(&herInt)”, which is equivalent to an ordinary identifier, such as “hisInt” in the code above . For a function parameter type, such as in “int theFn(int &no)”, above, the identifier used in the calling function is “theInt”. Note: you send the ordinary identifier and not the value of the object.

The summary for * is not so straight forward; it is in three phases: a) For initialization, function parameter and return type, you send a pointer identifier (address, i.e. &identifier). b) After declaration (or initialization) you send an address to the pointer identifier, which is not preceded by *. c) After declaration (or initialization), you send the value or ordinary identifier that has an ordinary value, to the identifier of the pointer, preceded by *.

Important: pointers and references are used to economize memory; otherwise, you would have copies of the same thing in memory, in situations that you do not intend to have the copies.

Position of * or &
The question here is, should you place * or & near the type specifier or near the identifier, in a declaration? The answer is, it does not matter. So the following two expressions are the same:

        int *myInt =

        int* myInt =

Also, the following two expressions are the same:

        int &herInt =

        int& herInt =

Wow, we have learned something new. C++ has many exceptional features, for example, you cannot split “int &herInt = hisInt;” into declaration and assignment statements. Well, just be patient; when you finish reading all the C++ tutorial articles that I have in this volume you will surely like C++. You may also realize that these features are not really exceptional features; there are reasons why they should be that way; we just have not yet gone into the depths of C++ in order to understand. C++ is one of the best (if not the best) programming language in the world today. When many a new language is released, its standard is compared to C++. The only problem I know with C++ is that it has a few clumsy features. However, it is still a solid language. All what I have said in this article is applicable to instantiated objects from classes.

Well, that is what I have for References 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