Hello, and welcome back. In this lecture I want to talk about point arithmetic.
Now that we understand the relationship between arrays and pointers,
this concept is going to be easier to understand.
We say arithmetic, but we don't really --
all it really means is you can do either plus
or minus or incrementation or decrementation on a pointer itself.
So the real power of using pointers to arrays comes into play
when you want to sequence through the elements of an array.
You want to go from the first element to the end, you want to iterate through them.
This is the real power pointers. Because pointers point use addresses,
each element in array is just another address.
So you can just do plus plus on pointers and you can go to the next address.
So here values pointer can be used to access the first
integer of the values array.
It can be used to access values sub-0.
So if you remember values pointer is a pointer
that's pointing to an integer array.
And we assigned it to the first element in the array by just assigning the pointer to the array name.
We could also use the address of operator sub-0 if we wanted to.
But when we dereference values pointer
because it's pointing to the first element in the array,
it's going to give you the first integer in the value sub-0 array.
If you wanted to reference value sub 3
via the pointer variable, all you have to do is add 3 to the values pointer
and then apply the indirection operator to dereference it.
So you could just do something like this. You can say values pointer plus 3
and then dereference it with the asterisk.
And you usually put the asterisk outside of quotes to make it clear.
But what this is doing is it's saying values pointer,
which is an address of the first element in the array, it's adding 3 to it.
And so it's going to actually add for each bytes for integers,
it's going to multiply the bytes times the integers.
But this is essentially going to point to the
sub 3, the 4th element in the array.
So in the expression asterisk values pointer plus i
that can be used to access any value contained in a values array.
So if you understand this expression, you can add anything to i
and it will point you to a specific element array.
So if you want to set value sub 10 to 27,
all you have to do is if you're using a pointer
is say values pointer plus 10 and then dereference it and say equal 27.
So you see the different syntax here.
Again, it's notational convenience but it's also more efficient in terms of the program itself.
So pointers because they're so closely related to arrays,
you can easily access elements by just incrementing decrementing
pointers or adding values or subtracting values from a pointer.
Very, very useful.
To set values pointer to point to the second element of the values array,
you can apply the address operator to value sub 1 and assign the results to values pointer.
We saw this. This is just another way to do the same thing i mentioned earlier
if you want to use the address sub operator.
You can always do this if you want,
but it's much more convenient to do pointer arithmetic.
If values pointer points to value sub-0,
you can set at the point of values of one by simply adding one to the value of values
pointer. And this is really what we're getting at with point arithmetic.
All you have to do is say values point or plus equals one,
and now values pointer is pointing to the second element in the array
or the first index.
Very, very nice notation, very easy to do.
So this is perfectly valid expression in c
and can be used for pointers to any data type whether it's an integer character
or anything. And you probably should be thinking about how useful this can be in characters.
If you have a character pointer, you can now access each element,
each character in a string by just doing a plus plus on a pointer.
The increment and decrement operators plus plus and minus minus
are particularly useful when dealing with these pointers
because you will usually want to go from one element to the next and so forth.
It's not as common to add 22
or minus 20 because you're usually going in sequence.
So using the increment operator in a pointer has the same effect as adding one to the pointer.
Using the decrement operator has the same effect as subtracting one from the pointer.
So saying plus plus values pointer
is going to set the values pointer pointing the next integer in the values array.
Minus minus should be values pointer
Is going to set the values pointer pointing to the previous integer in the values array.
But you want to be careful when you do the minus minus
because you want to make sure that you're at least in the array and you're not at 0.
And the same goes for plus plus.
If you're at the end of the array, you don't want to have any out of bounds errors.
So make sure that values pointer if you're decrementing it,
it was not pointing to the beginning of the values array initially.
Another example here
where we're actually going to sum all the elements in array,
you see that we have an array sum function
and the function takes an array
and it also takes a constant integer as parameters.
Inside the function, we're going to create an integer.
We're going to initialize that integer sum to 0, and we're going to create an integer pointer,
a pointer to of type int.
We're also going to create a
pointer that's constant.
So what that means is you can't change the address of it.
It's always going to be array plus n and it's going to be named array end.
We're doing this because it makes our loop more efficient
if we set it up to go to the array end and just look at the pointer.
So array end is pointing to the address of the end of the array.
We can say array, which is what's passed in and then n
is the size,
the size of the array.
Now the for loop is going to initialize the loop control variable pointer,
which is a pointer to the array. And all you have to do is if you want to
assign a pointer to the first element of an array,
all you have to do is say pointer equals array.
And then our loop exit condition is if the pointer is less than the array end.
Remember, a pointer is an address and array end is also an address.
So we're saying if the address at pointer is less than pointer n,
then we want to execute the body of the loop.
Pointer is just a integer, it's a hexadecimal address.
Each time we increment, it goes to the next address. We have the ending address,
so we can say go through the loop until we hit the end.
And then we're incrementing the pointer itself,
which is going to increment the address to go to the next element in the array
essentially because that's what we're pointing to.
Then we have inside the body of our loop, we say sum plus equals pointer.
We're dereferencing the pointer to get the value
because remember we want to get the value we don't want to get the address of the pointer
or the address of the pointer is pointing to.
And then at the very end, we return the sum. So this is going to
sum all the elements in an array.
You'll notice in the main, we also did a declaration of the
function in there as opposed to the top of the file. I usually like to put them at the top of the file.
But in the main, we create an array of 10 elements, 3 7 negative 9 and so forth.
We then pass in the array or a sum,
and we specify the size as 10.
And what you're going to notice is it returns the value which is the sum of the array.
So it's very, very nice to use this point arithmetic to iterate through an array,
we can just
plus to the next address and also look at the ending address to jump out.
This is more efficient with the pointer looking at the ending address as opposed to
a counter looking at less than n.
And you also notice we created them as constants because the constants don't change
and that's more efficient with the compiler.
The array here is a constant pointer meaning that the address can't change.
You also should have noticed in this example
that to pass an array to a function, you simply specify the name of the array.
So we know how to pass raise the function. And to produce a pointer to an array,
you only need to specify the name of the array.
We saw that when we assign the first element of the array to a pointer.
So what this implies is that the call
to their array sum function what was passed to the function was actually a pointer to the array values.
And this really is telling you that arrays and pointers are very, very closely related,
that an array is nothing more than a pointer.
And this explains why you're able to change the elements of an array from within a function.
Because up until this point, when you pass in data to a function,
that data does not get changed outside of that function unless it's a pointer.
Because that's why we have to pass in the address for the scanf.
The only way that elements get changed outside of a function
are is if you're passing pointers to a function.
And because the elements are modified inside that function,
this implies that you're passing a pointer.
And this is just again proving that
when you that arrays and pointers are very, very similar in that arrays are indeed pointers
just using different syntax.
We're going to talk about how we can pass by reference
or really passing a copy of a reference,
which will allow you to change data in a function outside of that function.
If you remember from one of our previous challenges,
whenever we wanted to change data in a function,
we had to use a global variable.
Because we didn't understand the concept of
passing by reference and we didn't understand the concept of pointers.
But I mentioned earlier too one of the advantages of pointers are that
you can now change data inside of a function and it will get reflected outside of that function.
But that's another lecture.
But that concept in itself because of the previous example is demonstrating
how arrays are essentially pointers.
So you might wonder why the formal parameter inside the function is not declared to be a pointer.
Well, it could be. We could just do something like this, int array sum, int star array.
We don't need to declare that as an array.
It's perfectly valid because arrays and pointers are the same that we can say int star array.
We mentioned they're really closely related.
So you can declare an array type to be a type of array of ints
inside the array sum function or you can you can declare it as a pointer to int.
And that's why you see many functions that accept arrays as parameters
or as arguments where the parameters are actually pointers.
So if you're going to be using index numbers to reference the elements of an array that is passed to a function,
then declare the parameter as an array.
Again notational convenience, it's just a different way of the notation,
either using the brackets and subscript or using a pointer.
The array itself is usually easier to read
in terms of maintenance of the program it more correctly reflects the use of the array by the function.
But the pointer is easier to use.
And if you're using an argument as a pointer to the array, declare it to be of type pointer
in the formal parameter.
So here's an example with the pointer notation of the function
where the previous example was using an array notation.
Here we just say int start array
and what you'll notice is the function immediately becomes a lot smaller,
because we don't have to assign the pointer to the array
to the first element like we did.
The loop also becomes a lot smaller because we don't
need to do that assignment in the first statement.
We can just say until the array is less than array end
and we can increment the array. So it's a little less code,
it's still very clear what's going on hopefully if you understand arrays and pointers.
We're passing in int star array,
and we don't have to initialize that array anymore because
we're passing it in the pointer, we don't initialize the pointer anymore.
And then we're actually setting the address of the end of the array
to a constant pointer,
array end. We use that to jump out of the loop,
and we just say sum plus equals star array,
using the indirection operator to dereference the array again, returning the sum.
And then the main function is exactly the same except the declaration is now a pointer as opposed to an array.
So here are 2 examples using different notation but providing the same functionality
and that's why you see a lot of pointers as parameters inside of
a function parameter.
So to summarize here are some things that are valid when you
use pointers and things that are not valid.
So if we declare some variables here, we declare an array called earn
and it's contained 3 elements and then we declare 2 pointers.
Now on those pointers, we can do arithmetic. We can say pointer one plus plus.
We can say point or 2 equals point or one plus 2.
We can even say pointer 2 equals earn plus one.
It's perfectly valid to do that because you have pointers and you're modifying the pointers by the
address, so you can do point arithmetic.
You can't do point arithmetic on arrays. So you cannot say earn plus plus.
You cannot say pointer 2 0.2 plus 0.1
because those are addresses.
And you're not actually
pointing to anything inside of an array.
And you can't multiply earn times point or one to get point or 2.
Those are invalid.
So pay attention to the correct syntax for pointer arithmetic
and also understand that point arithmetic can only be applied to pointers,
not arrays.
Also functions that process arrays actually use pointers as arguments.
You have a choice between array notation and pointer notation
for writing array processing functions.
So if you're going to process the random function it's perfectly fine to use a pointer as a parameter.
You can choose which one you want to use.
But using pointers is usually less code and more efficient.
Using array notation makes it more obvious that the function is working with arrays
and array notation has a more familiar look to programmers that have
some programming background in certain languages.
So if you program before and Fortran and Pascal and so forth,
you may use the arrow notation.
Other programmers might be more accustomed working with pointers and might find the pointer notation
more natural, just makes more sense.
It's closer to machine language using the point arithmetic
and the pointer notation with some compilers it leads to more efficient code,
another reason to use it.
So let's take a look at these examples inside
code blocks.
So here's our example from the slides. We have our function declaration up on line 3.
It's an array sum.
And in this example, we're going to use array notation.
So we're going to use the brackets when we use indexes.
And we're going to call it
passing in the values array and passing in the size.
So the array sum function takes an integer array. Well,
first thing you have to do is you have to create the pointer that you want to use
for point arithmetic on line 14. And then you have to assign
the end of the array to the address array plus the size.
That's the end of the array, which you can now use to exit the loop.
But we have to assign the pointer to the array.
We know that we can assign arrays to pointers
to point to the first element by just using the name of the array.
We don't have to use the address of operative.
We could if we wanted, we could actually do something like this.
And this is fine as well.
And then we plus plus the pointer. We're incrementing the pointer because all that's
doing is incremented to the next address. It's pointing to the next element in the array.
And then on line 18, we're dereferencing the pointer to calculate the sum,
sum equals, sum plus the value of the pointer that it's pointing to.
So if we build this we do have one warning,
which is main is not an int, we want to change this
because it's good to return error values from the main
and just say return 0.
You could return if there was an error in main,
you return a negative one. Now we run this, you'll see that it just performs the sum of the values in the array,
which is 3 plus 7 plus negative 9 and so forth,
not even sure what that is but it looks like it's 21.
Now we can easily modify this array parameter to
take a pointer by just declaring the asterisk before the pointer.
We call it the same way. We just modify. We don't need to declare
the pointer anymore. We probably want to change the name
to make it easier, but we don't need to declare this pointer anymore.
We still want to get the end of the array
and we don't need to assign it anymore either.
We can just have an empty thing there. And it might actually be more useful to have a while loop here.
But if we have no assignment we can just put the semicolon there.
And now we're good. We still want to de-reference it and we still want to return it.
But if we build this,
we want to make sure that
we define the function declaration as a pointer since we changed it.
And this can be any name but we'll just be consistent.
Now we build
we want to make sure that we're again
using all the variables that we changed.
So now we built successfully we run it and you see
you get the same result which is 21.
So understand this difference between using pointers as formal parameters
in arrays,
you can use them interchangeably. It's just a notational convenience.
But you have less code usually, when you use a pointer.
And you can manipulate it more and you can do more powerful things,
it's usually more efficient too based on the compiler. Thank you.