In this video, we'll learn more about function parameters, and we'll also
talk about the return statement.
When we call a function and pass data into that function, this data
are the parameters to that function.
In the function call, these data are called arguments.
In the function definition, they're called parameters.
We'll define the vocabulary more precisely in the next slide.
As we've already seen, when we call a function, the arguments we use to
call the function and the parameters that the function expects must
match in number, order and type.
Let's see an example.
In this example, we have a function prototype that tells the compiler
that we'll define a function named add numbers that expects two
integers and returns an integer.
Then in the main, I declare an integer variable named result,
and we initialize it to 0.
Then we call the add numbers function and pass in the
integer literals 100 and 200.
The compiler will type check this function call to be sure it's valid.
Since I'm passing in two integers and the function prototype says
exactly that, then the compiler will not produce an error.
You can see at the bottom of the slide, that I've defined
the add numbers function.
It has two integer parameters, a and b.
In the case of the function call in main, a will be 100
and b will be 200.
100 plus 200 is computed and 300 is returned.
The 300 is then assigned to the variable result in the main function.
Let's take a look at another example.
In this example, I didn't provide a function prototype to save space.
But you should know at this point that it would be void
say hello standard string.
Notice that the function say hello expects one parameter,
and it's a c++ string object.
And it displays hello followed by whatever string is in the name object.
The next three statements would normally be in
main on another function.
These are the function calls.
The first is say hello Frank.
Notice that frank is a c-style string literal, but the function
expects a c++ string object.
Aren't these types different.
Why doesn't the compiler produce an error here.
Yes, the types are different.
But the compiler will try to convert one type to another if it knows
how to make the function call work.
In this case the, c-style string literal Frank is converted
to a c++ string object.
The same would happen if a function expected a double
and I passed an intent to it.
The int would be promoted to the double as we've already seen.
Notice the last function call.
In this case, I'm calling the function say hello with a single
string object parameter, my dog, which is a variable name for a string
object with the string buster in it.
Let's talk a bit about how parameters are passed into functions.
In c++, when you pass data into a function that data is passed by value.
What this means is that the value of the data is passed in by copy.
So the compiler makes a copy of the data.
That means that the code in the function does not change the
argument that was passed in.
When we finished the function, the original data that was in the
function call will be unchanged.
This is good and not so good.
It's good because since we're making a copy, we can't change the original
argument by mistake or intentionally.
It's not good because sometimes making a copy of data can be expensive
both in storage needed and in time needed to actually copy that data.
Also, sometimes we really do want to change the
actual data being passed in.
Fear not, c++ has solutions for all these use cases, and
we'll learn about them soon.
Let's define some vocabulary used in programming languages, that is
formal versus actual parameters.
Formal parameters are the parameters defined in the function's
definition, in the function header.
Actual parameters are the parameters that are used when
the function is called that is in the function call statement.
Many programmers and languages call actual parameters the
arguments to a function.
In c++, the actual parameters are passed by value or copied
to the formal parameters.
Let me show you an example that will make this clear.
In this slide, I have a function definition for a
function called param test.
And this function expects one parameter called formal.
This is an example of a formal parameter.
If this function expected more than one parameter, they would all
be considered formal parameters.
In the main function, I'm declaring an integer named
actual and initializing it to 50.
I'm displaying actual which will display 50.
Then I'm calling the param test function with the actual parameter.
This is the function call.
Any parameters passed to functions here are considered actual parameters.
In this case, the value of the actual parameter is copied
to the formal parameter.
So formal in the param test function will have the value 50.
But it's at a different location in memory than the
actual since a copy was made.
I then display formal and param tests, so 50 is displayed.
Then I assign 100 to formal and display it again.
So you see 100 is displayed.
Now the function is done, and we return back to
main, and we print actual.
Actual will still be 50.
It was never changed because param test was working
with a copy all along.
It's very important that you understand the concept of pass
by value since it's critical to understanding functions.
Let's talk about the function return statement next.
As we've already seen, if a function is defined as returning
a value of a specific type, then the function must return a value of
that type using a return statement.
We've already seen a few examples of this, and we've been doing it
in the main function all along.
If the function return type is void, then the return statement is optional.
A return statement can occur anywhere in the function body,
but you usually see it as the last statement of the function body.
The return statement immediately terminates the function.
It's possible to have multiple return statements in a function
depending on the logic in your code.
However, this is not a best practice.
You typically want a single return statement.
Remember, having multiple break statements in a loop
and the potential problems you could have with readability.
Well, the same is true with multiple return statements and functions.
Finally, if the function returns a value, then this value
becomes the result of the code that's called the function.
Let's head over to the IDE and see some examples of parameter
passing and pass by value.
Okay, I'm in the IDE, and I'm in the section 11 workspace in
the function parameters project.
In this example, what I'd like to do is go over some simple function calls
that pass in parameters by value.
And I want to make the point and hopefully you'll understand that those
by value parameters do not change.
That's really important to understand.
So I've got four function prototypes here.
The first one is called pass by value one, the second is
called pass by value two.
And the first one just expects an integer, the second one
expects a c++ string object.
The pass by value three function expects a vector of string objects.
And the last one print vector just prints out a vector.
So if you send it a vector of strings it displays all
the strings in the vector.
Okay, o let's look at it the first one, pass by value one.
It expects a number and the parameter name for that number is
num, that's the formal parameter.
And all I'm doing is changing num to a 1000.
Really, really simple.
So let's look at my main.
In my main, I've got num, which is 10.
And I'm simply saying num before calling about pass by value 1 is
hopefully, that'll print out a 10, right, that's what we expect.
Then I'm going to call pass by value, and I'm going to
pass into it num, which is 10.
Remember, pass by value 1 changes that value to a 1000.
And then I come back and i print out that number again.
Now you may think that we're going to get a 1000, here but we're not.
It's passed by value.
So we actually passed in a copy to that function.
So the function was changing the copy, not the actual which is this num here.
So let me run this, and then I'll walk you through exactly what's going on.
You can see here none before calling 10, num after calling still 10.
Okay, so let's talk about that.
Remember, num is equal to 10 and it's in my main.
So in this case, here's my main function.
And it's got a local variable in there called num, and
we initialized it to 10.
Then we called this function right here.
So this would be passed by value one.
And I'll just call it one.
Okay, just to save some writing time.
So that's passed by by value one.
And it expects an integer num.
So it's got its own copy of num.
That's the formal parameter.
And at this point, the 10 gets copied over to num.
Okay, now I'm going to set num to a 1000.
Remember, this num right here refers to that guy, not this one.
So I'm changing the local num, the formal parameter to a 1000.
So I'm just changing this one to a 1000.
I never touched this one.
Now this function is finished.
So this function is now finished.
This is gone and, I'll talk about what gone means in a couple
of videos when I talk about activation records and the stack.
That's it. Now we return.
And in the main, we display num, well num never changed.
Remember, this was an absolute copy of it.
And so hopefully, that makes sense with pass by value.
Let me show you another example.
Here we've got another num, which is 20.
So don't get confused with the names.
I could use any name I want in that formal parameter.
I just chose num to make a point.
In this case, it's another num.
So when we pass -- when we print here, we're going to print to 20, then
we're going to call pass by value 1 again and pass in that num, so the 20
gets copied to the formal parameter.
We change it to a thousand.
Again, we change that local copy.
And when we come back, we still have a 20, right.
We never touched the actual.
So let me run this.
And now, we're going to see 10 10 and 20 20, just what we expect.
It's no different when you use objects.
So in this case, I'll uncomment that code.
In this case, you can see that I've got a string, a c++
string object called name.
And I've initialized it to Frank.
And then before I call pass by value 2, I'm going to display it.
That's going to display Frank.
Then I'm going to pass that string object into pass by value
2, which is another function, and that function is right here.
It's going to change its parameter to change, whatever
was there before is now changed.
And then when I come back, I'm printing out name again.
Name has not changed because that changed here, changed a copy.
Okay, so let's walk through this one again.
So what do we have.
We have main,
we've got the main function, and it's got a variable
called name, and it's Frank.
Okay, then we called pass by value 2.
So this would be passed by value 2, and it has a parameter,
right, a formal parameter, which is a variable, it's called s.
And we copied Frank in there.
So right now this becomes Frank.
Now we say s is changed.
So we get rid of Frank, and we replaced it with changed.
And again, these are all strings, string objects.
Now we return back to main, this function is now done.
I never changed the name because I never even knew about it.
I was working with a local copy all along.
Okay, so it's same thing with integers as with objects.
So in this case, if I run this program, you can see the name before
calling pass by value 2 is Frank.
And the name after calling pass by value 2 is Frank.
Again, it hasn't changed.
All right, let's do one more just to drive this point home.
This is really important that you understand what's going on here.
In this example, I'm using a vector of string objects.
I don't think we've used a vector of string objects.
We basically used, I think, vectors of integers and doubles.
We can have a vector of anything.
So here, we're saying that stooges is a vector of strings.
And the strings in that vector are Larry, Moe and Curly.
So I'm printing out stooges before calling pass by value 3.
And I'm calling this function called print vector that just
prints out those strings in that vector, whatever they happen to be.
Then I'm calling pass by value 3, and I'm passing in stooges and then
I'm just printing it out again.
Okay, so let me run this first, and then we'll walk through it.
So you can see that before calling the function: Larry, Moe and Curly.
After calling that should say, after right there, after calling
the function Larry, Moe and Curly.
Okay, so let me change that and make that correct that way.
When you guys see it in the resources, you'll know what I'm talking about.
So let me run that again.
Okay, so before calling Larry Moe Curly, after calling
Larry Moe curly.
So let's walk through this example.
Here is the function pass by value 3.
So in this case what have I got?
Well, I've got my main, and my main has the stooges variable,
which is a vector of strings.
In this case, it's Larry Moe and Curly.
These are all string objects.
Right now, I call this function right here.
And I pass in stooges to it.
So this is pass by value 3, and it has that formal parameter v.
That could be any name we want.
Right now Larry Moe and Curly get copied into v.
So this will be Larry Moe and Curly.
Now I execute this line right here v.clear.
That deletes these guys.
So now v is empty.
And that's it.
Then I return back to main.
What happens?
This function is now gone.
And when I come back to main, it still has that stooges
vector Larry Moe and Curly.
I never touched it.
Because again, I was working with a copy.
In the next few videos, we'll learn how to send information in so that
I can modify the actual parameters.
But it's important to understand that by default this is the
behavior pass by value, make a copy.
Okay, so hopefully that makes sense.
And if there are any questions, please post them on the course forums.