I’m on the 10th day of my #100 Days of Code challenge. In the challenge I’m focussing on learning C++ programming language. Two key parts of this language are things called References and Pointers. They’re a little confusing at first, and then they seem to become more confusing. But it’s helped to write my own  simple programs that illustrate what Pointers and References are and how they’re used.

This isn’t an in-depth all encompassing tutorial. It’s just brief summary notes illustrating basic use. If you’re learning C++ it’s probably most helpful if you create your own examples similar to below.

The below assumes some knowledge of C++ language and terms like scope, function, variable, pass (a variable), address.

The complete examples at the end of this post do compile and run. But if I’ve made a mistake, please let me know and I’ll correct it.

What is a Pointer?

A Pointer is a variable that holds a memory address. The address is where the value of a normal variable is stored. The following diagram illustrates the relationship between variable, value, address and pointer:

  • both normal variables and pointers are variables,
  • each variable has a memory address (var has 1001, ptr has 2047),
  • each variable has a value (var has 50 and ptr has 1001),
  • ptr’s value is the address of var.
  • So, whenever we refer to the pointer, we’re referring to the value of var.
c-var-ptr
(image source)

What is a Reference?

A Reference is essentially the same as a pointer, except they:

  • have slight differences in the way they’re declared and used, and
  • are a bit simpler, and offer less possibilities for advanced programming than pointers.

The important thing is this: both Pointers and References hold the address of another variable.

So, why does that matter?…

Passing by Reference

A common thing to do in a program is send a variable to a function, to do something with that variable. For example add two numbers together.

If we pass the variable directly to the function (called “passing by value“), C++ will:

  • copy the value of the variable,
  • use the copy in the function, then
  • delete the copy.
  • The original value remains unchanged.

This is fine in a lot of cases, but say we want to change the value of a variable that is not within the scope of the function in which we manipulate it. (This can happen if we have a variable that is used by several functions.) Passing by reference allows us to do this.

A reference is a variable that holds the memory address of another variable. As above, there are two types of these variables in C++; one is called a pointer, and the other is called a reference (confusing!).

When we pass a value to a function by reference (ie by referring to the address of the value), C++ will use the reference to work directly with the value of the variable we’ve referenced. If the function changes the value of the variable, that change will remain once the function has finished running.

There are three ways (that I know of) to pass by reference. These are summarised in the Super Helpful Syntax Cheat Sheet (table) below!

Carl Turner PointersReferences table

For more completeness, here are two of the better explanations I’ve found:

Examples of passing by reference

For brevity I’ve left off the following three lines from the following four examples.

#include <iostream>
#include <string>
using namespace std;

 

1. Pass a pointer

  • declare a function that takes a pointer argument, then
  • pass a pointer to the function.
//'*' indicates a pointer 
//'&' indicates 'the address-of'
void PrintNamePtr(string *_name){
cout << "Name is: " << *_name << endl; //prints Name is: John
}

int main(){
string name = "John"; //declare a string with value of John

string *pName = &name; //declare and initialise pointer called pName
PrintNamePtr(pName); //Pass the pointer to the function.
}

 

2. Pass a Reference

  • declare the function to take a reference argument, then
  • pass the variable directly to the function.
  • (the function reads the variable as a reference)
//'&' indicates declaration of a reference (not 'address-of' - confusing!). 
//Normally you have to initialise references when you declare them.
//When declared as a function parameter, the reference is 
//initialised when the function is called.
void PrintNameA(string& _name){
cout << "Name is: " << _name << endl; //Prints Name is: John
}

int main(){
string name = "John"; //declare a string with value of John
PrintNameA(name); //Pass by reference, using the variable
}

3. Pass a pointer argument

  • declare a function that takes a pointer argument, then
  • pass the address of a variable, as the argument, to the function.
//'*' indicates a pointer 
//'&' indicates 'the address-of' 
void PrintNamePtr(string *_name){
cout << "Name is: " << *_name << endl;   //prints Name is: John
}

int main(){
string name = "John"; //declare a string with value of John
PrintNamePtr(&name); //Pass the address of name to the function.
}

A little more on References

Earlier I mentioned there are two types of variable that hold the memory address of another variable – pointers and references (not to be confused with pass by reference, which can involve either pointer or reference variables).

A reference is an alias. In other words it’s just another name for an existing variable, like a nick-name I guess. A reference to a variable can be used in the same way as the variable.

The below example shows a reference in use. It’s the same as the second example above, but with two lines added to main(). The important thing to note is that when declaring a reference the ‘&’ symbol is used, and in this context it does not mean ‘address of’.

//'&' indicates declaration of a reference (not 'address-of')
void PrintNameA(string& _name) { 
cout << "Name is: " << _name << endl; //Prints Name is: John 
} 

int main(){
string name = "John"; //declare a string with value of John

PrintNameA(name); //Pass by reference, using the variable

string& rName =name; //declare and initialise reference (alias) to the player's name, called rName.
PrintNameA(rName); //pass by address, using the reference
}

Complete source file examples

Download two complete examples here: https://goo.gl/jDuaAc

Or check out the full code below.

Pointers: complete example 

//
//  main.cpp
//  SimplePointers
//
//  Created by Carl Turner on 21/8/18.
//  Copyright © 2018 Carl Turner. All rights reserved.
//

//Simple example of pointers
//A pointer is a variable that holds a memory address.
//This program illustrates simple use of pointers. For something as simple as this it's slightly easier to use references, rather than pointers.
//Because, in order to pass a pointer to a function, the function must be declared as taking a pointer as one of its parameters. Whereas a reference is just an alias and can be passed to the same function as you'd pass the variable it references.

#include <iostream>
#include <string>

using namespace std;

struct playerCharacteristics
{
    int health = 10;
    bool alive = true;
    int score = 5;
    string name = "John";
};

void PrintName(string _name)
{
    cout << "Player's name is :" << _name << endl;
}

//to pass a pointer to the function, the function parameter must be declare as a pointer
void PrintNamePtr(string *_name)
{
    cout << "Player's name is :" << *_name << endl;
}

void UpdateName(string _name, string _newName)
{
    _name = _newName;
}

//to pass a pointer to the function, the function parameter must be declare as a pointer
void UpdateNamePtr(string *_name, string _newName)
{
    *_name = _newName;
}

int main() {
    playerCharacteristics player;   //instantiate a player
    string *pName = &player.name;    //declare a pointer to the player's name. Call the pointer 'pName'.
    
    //The following lines show you can use either the pointer or the actual variable name to retrieve the player's name. BUT in order to change the value of player.name we need to use the pointer OR the address of player.name (ie &player.name).
    cout << "1. (Get name, using pointer): ";
    PrintNamePtr(pName);               //pass the variable by pointer to its address. name is John
    
    //When we pass by value, a copy of the value is sent to the function. The original value is not changed
    cout << "2. (Try to change name to Sam, by passing by value): ";
    UpdateName(player.name, "Sam"); //pass the variable by value. Name is still John.
    PrintName(player.name);
    
    cout << "3. (Change name to Sam by passing address of the variable itself):  ";
    UpdateNamePtr(&player.name, "Sam");       //pass the address of the variable name itself. Name is updated to Sam. Because we passed the address of the variable we want to update, not a copy of the value.
    PrintNamePtr(&player.name);
    
    cout << "4. (Change name to Tim by passing address, using pointer):  ";
    UpdateNamePtr(pName, "Tim");  //pass by address. Name updated to Sam.
    PrintNamePtr(pName);
    
    return 0;
}

 

References: complete example

//
//
//  main.cpp
//  SimpleReferences
//
//  Created by Carl Turner on 21/8/18.
//  Copyright © 2018 Carl Turner. All rights reserved.
//

//Simple example of reference
//A reference is an alias, that allows making changes to variables from outside of the scope they exist in.

#include <iostream>
#include <string>

using namespace std;

struct playerCharacteristics
{
    int health = 10;
    bool alive = true;
    int score = 5;
    string name = "John";
};

void PrintName(string _name)
{
    cout << "Player's name is :" << _name << endl;
}

void PrintNameA(string& _name)
{
    cout << "Player's name is :" << _name << endl;
}

void UpdateName(string _name, string _newName)
{
    _name = _newName;
}

void UpdateNameA(string& _name, string _newName) //first function parameter is an address
{
    _name = _newName;
}

int main() {
    playerCharacteristics player;   //instantiate a player
    string& rName = player.name;    //declare a reference (alias) to the player's name. Call the alias 'rName'.

    //The following lines show you can use either the alias or the variable name in the same way.
    cout << "1. (pass by value): ";
    PrintName(rName);               //pass the reference by value. name is John
    
    //When we pass by value, a copy of the value is sent to the function. The original value is not changed
    cout << "2. (pass by value, using the variable): ";
    UpdateName(player.name, "Sam"); //pass the variable by value. Name is still John.
    PrintName(player.name);
    
    cout << "3. (pass by value, using the reference):  ";
    UpdateName(rName, "Sam");       //pass the reference by value. Name is still John
    PrintName(rName);

    /*The following lines use a function that takes an address. BUT you still pass either the alias or the variable name in the same way.
     When the function takes an address, it is the original value that is used/changed by the function*/
    cout << "4. (Update name: pass by address, using the reference):  ";
    UpdateNameA(rName, "Sam");  //pass by address. Name updated to Sam.
    PrintName(rName);
    
    cout << "5. (Update name: pass by address, using the variable):  ";
    UpdateNameA(player.name, "Tim"); //pass by address. Name updated to Tim.
    PrintName(rName);
    
    cout << "6. (Print name: pass by address, using the reference):  ";
    PrintNameA(rName);
    cout << "7. (Print name: pass by address, using the variable):  ";
    PrintNameA(player.name);
    return 0;
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s