C++ Programming Series: References

I believe that my series is getting complex with every post being published! This has to be done because we should also be getting more complex and more logical with every topic we discuss.

Today’s topic is References. Before proceeding on, let us discuss few problems with functions. The first one is that we don’t know any methods of getting multiple outputs. The second one is that we don’t make any change in the variable that we pass into the function via parameters.

The following code expresses the second problem with functions:

void multiplyBy2(int variable)
{
  variable *= 2;
  //No returning
}

int main()
{
  int variable = 2;
  mulitplyBy2(variable); //This should change the variable's value to 4
  cout << variable << endl; //Prints 2, not 4
  return 0;
}

NOTE: We can have same names for variables having completely isolated scopes. Note that multiplyBy2 has a parameter called variable and main function also has a variable called variable. Sounds confusing!

We have a solution for that and that is, to return that variable in the function and then, put that into any variable or just call that temporary return value directly.

But we expect the method above to change the variable’s value which is not the case here! Why? Well, the point is that when we pass the variable via the parameter of the function, we are actually copying that variable into another completely new variable. This new variable has a very limited scope i.e we can only access it inside the function.

Let us discuss a very simple example of what copying is:

int value1 = 2;

int value2 = value1; //Here, value1 is copied into value2
value2*=2; //value2 is a different variable; it will not effect value1 in any case!

cout << value1 << endl; //Prints 2, not 4
cout << value2 << endl; //Prints 4

The highlighted codes shows what is actually happening in the function, multiplyBy2() in the example, given above.

How to do it in the way that we want? The answer is right inside the topic of this post: References. There is another way and that one is through Pointers which is way more complex but we will discuss it later on.

What is a reference? Reference is just another name given to the same variable. In our real life, we can have the reference case of a bird called ‘raven’. Raven is a black bird. So, people can refer to ‘raven’ by calling it as ‘black bird’. In a very similar way, variables can have references as well.

//Consider that there is a bird called 'raven'
int raven = 10;

//That 'black_bird' is a reference to 'raven' 
int& black_bird = raven;

//Now, what we do with 'black_bird' is actually,
//what we are doing with 'raven' as well and vice versa...
black_bird*=2; //Both gets 20
raven+=5; //Both gets 25

cout << raven << endl; //Prints 25
cout << black_bird << endl; //Prints 25

The highlighted line shows how to make reference to a variable. It is pretty simple; just put ampersand or ‘&’ after the type of the variable that we are going to refer to.

int& is considered a type which we can call as ‘reference to an integer’. Same will be for any type reference as well.

Time to make some change in the multiplyBy2() function!

//Notice the ampersand before the variable's name
void multiplyBy2(int& variable)
{
  variable *= 2;
}

int main()
{
  int variable = 2;
  mulitplyBy2(variable); //Now, we are not copying, we are referencing!
  cout << variable << endl; //This time, it prints 4
  return 0;
}

Now that, the second problem is solved, the first problem is solved as well. We can have multiple outputs by having more parameters to the function. These parameters are going to be references and whatever is going to be changed with these references, this change is going to happen with the actual variables which are passed as parameters in the function.

//The first two parameters represent inputs
//and the next three represent outputs
void get3TimesDivision( float number1, float number2,
float& division1, float& division2, float& division3 )
{
  division1 = number1 / number2;
  division2 = division1 / number2;
  division3 = division2 / number2;
}

int main()
{
  //Multiple Outputs using References
  float div1 = 0.0f, div2 = 0.0f, div3 = 0.0f;
  get3TimesDivision( 8.0f, 2.0f, div1, div2, div3 );

  cout << div1 << endl; //Prints 4
  cout << div2 << endl; //Prints 2
  cout << div3 << endl; //Prints 1

  return 0;
}

Note the point that where we want to have references, we cannot have constants or temporary values there. In the above case, if the parameters, number1 and number2, are references to float, we cannot pass 8.0f and 2.0f into the function. We must pass variables of type float with the respective values, into the function.

That’s all! References are a great way to deal with outputs. Just try to modify all the previous functions that we created together, to have references and not copies. Practice them very well. They are going to be used extensively!

C++ Programming Series: Functions/Subroutines (Part 4, Last)

In the previous post, I confused you into the depth of the functions and my abstractions although, I hope that you got the concept fairly. The hint that I gave you in the previous post┬áis about the order of the functions. If you modified checkRegistrationEligibility() function by adding enterAString() and enterAnInt(), you may have got some error because checkRegistrationEligibility() function don’t know anything about enterAString() and enterAnInt() since, they are both defined as well as declared below the function. The issue with the order of the functions can be fixed but I will explain this later!

The functions with which we get father’s name, place of living and education in the previous post are very similar to each other. In fact, they are just the same with the exception to the statement being printed out!

Fortunately, there are more ways! Until now, we are just getting outputs from the functions in the form of returning values. But in many cases, it is necessary to have inputs in the functions. If you recall the first post on the topic of Functions/Subroutines, we discussed that a function takes the input, modifies it and then, outputs the modified input. We can always have the user input but there are many many cases where user input is not the solution! A pair of round brackets after the end of each function is not useless; it is for taking data into the function(inputs) or in other words, for taking parameters.

I had given you the task for creating a function which takes the user input for the number to be squared and then, returns the square of that number. Here it is done with a function that takes the input from the parameter, squares it and then, returns it.

int square( int value ) //a parameter of type 'int'
{
  return (value * value);
}

int main()
{
  //In 'square' function, we pass 5 as a parameter, giving us 25 as a return value.
  cout << square(5) << endl; //Outputs 25
  return 0;
}

This might have given you the idea of how parameters of a function works. Let us remove the three functions as described in the previous post namely, enterYourFatherName(), enterYourPlace() and enterYourEducation() and replace it with only one function!

string enterRequiredData( string required_data ) //a parameter of type string
{
  string data = "NULL";
  do
  {
    cout << "Enter your " << required_data << ": " << endl;
    data = enterAString();
    cout << "Is your " << required_data << " " << data << "?" << endl;
 
  } while (!isDataSure());

  cout << "Your " << required_data << " is " << data << "." << endl;
  return data;
}

Now, in the registrationSection() function:

void registrationSection()
{
  enterRequiredData("father\'s name");
  enterRequiredData("place of living");
  enterRequiredData("education");
}

All the other codes will remain same! You can see that a single function is doing quite a job because of the fact that it is more flexible now. The output of a function should depend on the parameters being given into it or else, the function should have no inputs/parameters at all. However, it is not necessary to use the output of a function for something else. In the codes above, we haven’t used the strings being returned by the functions inside the registrationSection(). We can store them in a separate file which is the prime purpose of registration (We will discuss about getting data into and out of a file soon).

That’s all! Function parameters are awesome! But there are still few problems that we may encounter, the first one is the order of functions and the second one is getting multiple outputs. You haven’t seen any example of multiple inputs/parameters as well. There you go!

int clamp(int value, int min, int max)
{
  if(value < min)
    return min;
  else if(value > max)
    return max;

  return value;
}

Try to code functions with multiple parameters and have fun with them!