Reputation: 3095
I thought I understood pointer syntax but there are small occurrences that throw me off, for instance:
int *ptr;
int array[4] = {1,2,3,4};
int *arrayEnd = array + n;
for (ptr = array; ptr < arrayEnd; ++ptr)
sum += *ptr;
return sum;
How come we do ptr = array
instead of *ptr = array
when defining the for
loop?
I also don't understand why when an argument to a function is a pointer, we don't use the asterisk.
I see this function(ptr);
in books, but why not this: function(*ptr);
.
Upvotes: 0
Views: 196
Reputation: 61
Notice the asterisk meaning is different in definiton. when you write:
int *arrayEnd = array + n;
it is actualy the same as:
int *arrayEnd;
arrayEnd = array + n;
In both cases you initialize the address of the pointer and not the value referenced by the pointer
Also note that when you define an array the array name can be considered as the first memory location of the array while the number in brackets is its offset i.e. the next two lines are the same:
ptr = array;
ptr = &array[0];
and also the next two lines:
array[2] = 5;
*(array+2) = 5;
Funny fact about the last example is that it can explain you can sometimes write:
2[array]
instead of array[2]
as *(2+array)
is the same as *(array+2)
So when you write:
int *ptr;
int array[4] = {1,2,3,4};
int *arrayEnd = array + n;
for (ptr = array; ptr < arrayEnd; ++ptr)
sum += *ptr;
return sum;
the third line placed the memory address of the last array
element in a variable called arrayEnd
the for
loop is running from the first array
location to the last array
location
the sum
adds the array elements
Upvotes: 0
Reputation: 1263
Assuming that you have code like below.
int x=10;
Here x is a variable that holds a value 10. The variable x is nothing but a label to some memory address.
x
+-------+
| 10 | 4050 which is x
+-------+
So value 10 is stored in 4050. Its always hard to remember memory address. So you make it easy by naming it and using that name.Here x is nothing but a label to memory address 4050.
int *x_ptr;
Here x_ptr is a pointer variable that can store memory address of any integer variable.
+-------+
| GBV | 5000 which is x_ptr
+-------+
Here x_ptr is a label for address 5000. Initially the variable will contain Garbage Value(GBV).
x_ptr = &x;
The above statement stores address of x in x_ptr.
+-------+
| 4050 | 5000
+-------+
x_ptr = &x = 4050
printf("%u",x_ptr); // 4050
printf("%d", *x_ptr); // 10
*x_ptr = *(4050) = valueAt(4050) = 10
Let us now discuss about your code.
int *ptr;
+-------+
| GBV | 6000 which is ptr
+-------+
int array[4] = {1,2,3,4};
+-----------+
| 1 | 7824 which is array+0 or array[0]
+-----------+
| 2 | 7828 which is array+1 or array[1]
+-----------+
| 3 | 7832 which is array+2 or array[2]
+-----------+
| 4 | 7836 which is array+3 or array[3]
+-----------+
Here array = 7824
int *arrayEnd = array + n;
Incrementation with memory location will increase no of bytes based on the data type.
array+0 = 7824 + 0 = 7824
array+1 = 7824 + 1(4 bytes in case of integer) = 7824 + 4 = 7828
when n=4
arrayEnd = 7824 + 16 = 7840
+-------+
| 7840 | 6010 which is arrayEnd
+-------+
for (ptr = array; ptr < arrayEnd; ++ptr)
sum += *ptr;
Here ptr is initialized with array's base address(7824). So 7824 will be stored in memory 6000.
6000 6000
+-------+ +-------+
| GBV | => | 7824 | 6000 which is ptr
+-------+ +-------+
so now ptr = 7824
For Loop
+-------+--------------+-------------+
| ptr | *ptr | sum + =*ptr | // 7824 < 7840
+-------+--------------+-------------+
| 7824 | *(7824) = 1 | sum += 1 | // 7828 < 7840
+-------+--------------+-------------+
| 7828 | *(7828) = 2 | sum += 2 | // 7832 < 7840
+-------+--------------+-------------+
| 7832 | *(7832) = 3 | sum += 3 | // 7836 < 7840
+-------+--------------+-------------+
| 7836 | *(7836) = 4 | sum += 4 | // 7840 !< 7840 so loop terminates
+-------+--------------+-------------+
Why ptr = array instead of *ptr = array?
valueAt(*) has to be used when you have to store some value in the memory address.
ptr= array; //initializing base address of array to ptr.
6000 6000
+-------+ +-------+
| GBV | => | 7824 | 6000 which is ptr
+-------+ +-------+
*ptr = array; // ptr already has a address pointed to, and you store array's base address inside that memory location.
6000
+-------+
| GBV | *ptr= *(GBV) = Unknown = array // No guarantee that GBV is a proper memory address
+-------+
if ptr already has some proper memory address say 1000, then it is like
6000
+-------+
| 1000 | *ptr= *(1000) = valueAt(1000) = array
+-------+
which makes
1000
+-------+
| 7824 |
+-------+
Simple example with multi pointers.
#include<stdio.h>
int main()
{
int x=10;
int *y=&x;
int **z=&y;
printf("%d --> %d --> %d",x,*y,**z);
return 0;
}
OUTPUT:
10 --> 10 --> 10
Upvotes: 1
Reputation: 7917
Let's begin with the first line of your code:
int *ptr;
If you had declared
int a;
What would it mean? It would mean a
is an int
. Similarly, since you have declared int *ptr;
, it means that *ptr
is an int
.
If *ptr
is an int
, what is ptr
? ptr
(without the star) is a pointer to an int
. A pointer is a variable that holds the address of a value. In this case, the pointer is a pointer to an int
, which means the value at the address held by ptr
is an int
.
Then you have int array[4] = {1,2,3,4};
. When you declare and define an array, the array identifier (the name of the array) tells you where the array lives in memory. When used in any expression, the name of the array decays to the address of the first element of the array.
So when you have
ptr = array;
you are assigning the address of the first element of the array to the pointer ptr
. Since this is an array of int
, you are assigning the address of an int
to a variable which can hold the address of an int
. The left- and right-hand side of the assignment are the same kind of value.
Why ptr
and not *ptr
? What is *
in this instance? It is the unary dereference / indirection operator. So
*ptr = array;
would mean: take the value on the right-hand side, and replace the value at the address held by ptr
with this right-hand side value. This is wrong for two reasons.
array
is an address. It is not exactly an integer value. It's just a location in memory. Sure, that location can be represented by an integer, the way a location in the US can be represented by an integer zip code, but just as you don't typically care what the numerical value of a zip code is, you probably don't really care what the integer value of a given memory address is either.ptr
is uninitialized. To go back to our earlier example: int a;
. What is the value of a
? We haven't set a value for it yet, so it has just garbage. Similarly, ptr
isn't pointing to anything yet. It can point to an integer, but we haven't yet told it what integer to point to. There is no address held at ptr
. We can't say "replace the current value pointed to by ptr
by this new value", because ptr
isn't yet pointing to any value at all; we haven't told it where to point to begin with. To sum up: By writing ptr = array;
what you are doing is precisely correct--assigning a pointer to an int
to a variable of type pointer to an int
. By writing *ptr = array;
you would be assigning an address to an integer, which is probably not what you mean to do; and secondly, since the integer itself is not allocated anywhere in memory, the assignment has nowhere to go.
That's why ptr = array;
is correct, and *ptr = array
would be quite wrong.
The question about function pointers is a separate one, so please ask a different question about func(ptr)
vs. func(*ptr)
.
Upvotes: 7
Reputation: 83527
Let's look at your suggested code:
*ptr = array
Remember that here, *
is the indirection operator. It returns the object at the memory location to which the pointer points. Also, in this context array
is converted to a pointer. So the above line assigns a pointer (i.e. a memory address) to the object ptr
points to. This can only be valid if ptr
points to a pointer. However, ptr
points to an int
instead.
On the other hand ptr = array
is correct because assigns ptr
to point to the first element in the array.
Upvotes: 1
Reputation: 8602
int *ptr, i;
int array[20];
ptr = &i; // make sure ptr points somewhere valid
ptr = array; // put the address of array[0] in the variable ptr
*ptr = array; // put the address of array[0] into the location ptr points to
ptr = array[0]; // put the integer in array[0] into the variable ptr
*ptr = array[0]; // put the integer in array[0] into the location ptr points to.
Upvotes: 1
Reputation: 476950
You can transform a traditional, index-based iteration into one using only pointer arithmetic like this:
T array[N];
// traditional:
for (size_t i = 0; i != N; ++i)
{
foo(array[i]);
}
// using pointer arithmetic
for (T * p = array; p != array + N; ++p)
{
foo(*p);
}
The pointer T * p = array
is obtained via the decay of an array name to a pointer to its first element. The connection between the two forms is the fundamental identity array[i]
== *(array + i)
.
Upvotes: 3