Hello, and welcome back.
In this lecture, I want to talk about a concept called pass by reference.
When we first started talking about pointers, I mentioned one of the advantages is
you don't have to use global variables as much.
Because when you pass a pointer to a function,
the functions can use that parameter. And when it modifies that parameter,
the data will be modified outside the function.
So this is a valuable, valuable concept.
We're going to talk about this. This is more of a concept. C actually doesn't employ this.
And I'm going to show you how and give you some examples
basically how this works.
So there's this concept of pass by value. This has to do with functions.
We talked about passing data to a function, but how is it actually passed
in terms of the language in the compiler.
So there's a concept of pass by value. And this is what we've been
talking about up until now. Whenever we call the function
besides the scanf function, but every other time we call the function,
when you modify that data inside the function
it didn't get modified outside the function.
So we talked about local variables that's kind of a different concept.
But when you pass data to a function, there's two ways you can pass it.
You can pass it by value, you can pass it by reference.
C does exclusively
passing by value and so does java,
all pass by value. But it simulates pass by reference
because you copy addresses.
And so even though this concept pass by reference
is not specifically employed by c,
it simulates it. And so to understand what pass by reference means
and why that's important we're going to talk about that.
But pass by value is when a function copies the actual value of an argument
into the formal parameter of the function.
And this is why if you have an integer,
a float or a double and you pass that in as an argument to a function,
that actual variable doesn't get modified outside the function because it's copied.
So changes made to the parameter inside the function have no effect on the argument.
The argument being passed in does not get modified.
So it almost acts like a local variable because it's a copy.
How it's actually happening under the hood is it's being copied and passed to the function.
C program uses call by value to pass arguments.
Everything is called by value pass by value.
These are used interchangeably these terms.
So again this means the code within a function cannot alter the arguments used to call the function.
There are no changes in the values though they had been changed inside the function.
It seems like they're local variables.
And that's why earlier up until this point
when you got to create global data if you wanted to share the data from one function to the next.
And this is how c works.
But what happens when you actually pass in a copy of
an address. Then it can mimic pass by reference.
But here's an example of how we've been using pass by value, it's demonstrated very nice here.
This swap routine is an often use case to demonstrate pass by
value because what it does is it creates a temp and it swaps the parameters
the arguments are being passed.
So if we have a function called swap that takes two integers,
we create a local variable temp.
If we assign to the parameter x to temp,
temp is going to be equal to x. If we say x is equal to y,
y is now going to be equal to x. If we say y equals to temp,
y is going to be equal to temp.
But when call this function
passing those values, x and y is going to be local to this function.
Those variables are not going to be modified outside this function.
And this function demonstrates it very useful because
we're assigning to y and we're assigning to x.
And x and y is local to this function because we're passing by value,
they do not get modified outside this function and that's why we have to use global variables.
But they're integers. They're two integers x and y. They're not addresses,
they're integers and that's significant.
So if we call swap
and we see what this is looking like,
you're going to notice that the values do not change.
So if we create a variable called a 100 b with 200
and we print out the variables before we swap,
100 and 200 then we call swap,
the variables are not going to be changed after we
print them out again.
So let's look at this in code blocks and this will demonstrate pass by value.
So here's our example. We have our swap routine.
We're swapping values of of data that's passed x and y.
We're calling it with 100 200.
We're going to print out before we call the function.
We're going to print out after.
And what you'll notice is the variables a and b never change.
And the reason for this is because we're doing pass by value.
So if I run this program,
we can see that before swap the value of a was 100 after you swap the value of a was 100
and the same for b 200 and 200.
And the reason for this is because we passed by value. If we passed by reference,
those variables a and b would change after the call to swap.
Now how about if we employ this same technique pass by value
but we copy pointers, what do you think is going to happen?
So pointers and functions get along quite well together.
You can pass a pointer as an argument to a function
and you can also have a function return a pointer as its result.
We're going to show how to do that as well.
But pass by reference copies the address of an argument into the formal parameter.
The address is used to access the actual argument used in the call.
So what this means is the changes made to the parameter inside the function
affect the argument that's in the call.
And so even though it's not technically under the hood passed by reference,
it mimics or simulates pass by reference.
We're copying the address. If you copy the address,
you have a new address and memory for that value the address.
But if you try to assign to that address, it's going to assign to the address.
So even though it's passed by value, it's copying.
And if you're copying a regular integer, you don't make changes. If you're copying an address,
the address is in memory so when you make changes you're going to make changes to that address.
So to pass the value by reference,
argument pointers are passed to the functions just like any other value.
You need to declare the function parameters as pointer types with the asterisk.
Changes inside the function are reflected outside the function as well.
You don't have to use global variables as much.
Unlike a call by value where the changes do not reflect outside the function.
We're still copying we're still passing by value it's just the value of a copy of the address.
So this is important concept to understand.
Now when we create our swap function,
we're going to create it with the declaration inside the
function as asterix, star and star.
That's saying that this function takes pointers.
Now when we assign inside this function,
we have to actually use the indirection operator
to dereference because we want to assign the values. We're going to assign the value that that x
that x points to the temp.
We're going to assign the value of x points to to the value that y
points to and then we're going to assign the value that y points to, to temp.
Temp is an integer so we don't have to dereference it.
Now when we invoke it
with a100 and b200
by passing in a and b, a and b are not pointers, so we have to pass
in the address because the function takes pointers.
Whenever you have a function that takes pointers and you don't declare a pointer,
you have to use the address of operator and it's the same thing as how we use scanf.
But now you're going to notice when we invoke this
after the call to swap the variables a and b are going to be changed,
they're going to be swapped. A is going to be 200 b is going to be 100.
So now let's look at this example with our swap method change to pointers in code blocks.
We're in code blocks. We modified the swap function to take pointers.
So we have to dereference them when we assign them.
We also now pass in the address of a and b because these are now integers,
and the swap now takes pointers. So when we run this,
we're going to see that the call and after is now going to be changed.
So before we call swap a is equal to 100 after we call swap is 200.
Before we call swap for b, it's 200. Afterwards, it's 100.
So we're able to change the values of variables
inside the function because we're making a copy of the address. Very, very important,
and one of the big advantages of pointers.
So let's summarize the syntax. I already did but let's go through in more detail.
You can communicate two kinds of information about a variable to a function.
You can transmit the value of x
and the function must be declared with the same type as x.
We know that. Whenever we pass data to a function,
we have to have the same types when we call it.
And here we have int function1 to invoke it and it's defined as an int num.
So when we transmit the value of x in the function they have to be declared with the same type.
And then if you want to actually invoke an address of x,
it requires the function definition to include a pointer to the correct type.
So whenever you use pointers, you have to make sure that if you're
passing in data and that data is not a pointer, you have to get the address of it.
What this is summarizing is if you define a function that doesn't take a pointer,
you can just call it and pass in the data.
Make sure it's not a pointer.
If you have a function that does take a
asterisk pointer,
when you invoke it, you have to invoke it with the add or sub operator.
You have to pass the address in.
That's the syntax.
Now you can also qualify a function parameter using the constant keyword.
This indicates that the function will treat the argument that is passed in for this parameter as a constant.
It's only useful when the parameter is a pointer.
Because if you're passing by value and you're not passing in pointers, it doesn't matter because
it's not going to affect the change on the outside
the function so why would you make it a constant, who cares if you change it.
The only reason you make a pointer constant is because you don't want to have
outside the function values changing.
And so you can apply the constant keyword to a parameter that is a pointer
to specify that the function will not change the value to which the argument points.
Very important.
So in this example we have a send message function. It takes a
a p message pointer.
We put the constant keyword before the char star.
So this type of parameter p message is a pointer to a constant character.
It is the character value that's constant, not its address.
So in this case what we're doing is the pointer that's being pointed to cannot change.
We can change the address, but we can't change what it's pointing to the value.
The syntax is similar to when we create constants on other pointers.
The constant keyword is it's the first thing showing then you can't change the value.
Now you could specify the pointer itself is constant,
but this makes little sense because the address is passed by value.
You cannot change the render pointer
in the calling function. So this is just if you try to make it so that the address couldn't be changed,
what's the point because it's passed by value.So you're actually making
a new memory location
to hold that specific address. So if you change it, who cares it's not going to change it on the outside.
You only want to be able to make the
parameter a constant so that you don't change the value
of what it's pointing to,
you can't change the original pointer and the calling function anyways because
it's passed by value passed by copy.
The compiler knows that an argument that is a pointer to constant data will be safe,
so there are advantages to this. You can't accidentally modify what the value is pointing to.
So you might do this again if you don't want the changes to be reflected on the outside of the function.
If you pass a pointer to constant data as the argument for a parameter,
then the parameter must be used like in the above.
When you invoke the function and you pass it into constant,
then you have to have the function declaration also take a constant character pointer,
just like normal other pointers that are constants.
They have to be defined and the defines have to match the prototype.
Returning pointers from a function.
Returning a pointer from a function is a particular powerful capability.
It provides a way for you to return not just a single value, but a whole set of values.
So again one of the other advantages I mentioned about
pointers is that you can now return more data from a function.
In the past, you can only return one value.
But with a pointer because a pointer could be pointing to
a structure which we haven't talked about yet or even other things
you can return multiple values
So we know how to pass pointers to functions,
now we want to talk about returning pointers.
You'd have to declare a function returning a pointer. So the function declaration has to match up.
It's very easy to do that. You just say use the asterisk when you
declare the function or define it and have the return type for that pointer what it's pointing to.
So be careful though there are specific hazards relating to returning a pointer.
Use local variables to avoid interfering with the variable that the argument points to.
It is somewhat problematic when you're returning pointers because if you modify that pointer
inside the function and then return it,
it could be something that you don't intend it to do.
So always use local variables if you do not want to affect
a variable that your argument points to.
And so this lecture described
how you can pass pointers to functions
and how you can return pointers from functions.
And by using this mechanisms of passing pointers to
a function it demonstrates or mimics pass by reference
because you're copying in an address.
And when you copy an address if you write to that address you're going to update
whatever is pointing to that address,
which effectively means that you're changing the value of
the data inside the function it's going to reflect it outside the function.
We use the swap routine to demonstrate that.
This is a very powerful concept. And you want to mimic pass by reference,
you can use pointers to do that and you want to do that when you want to change things outside the function.
Thank you.