I wanted some further understanding, and possibly clarification, on a few things that confuse me about arrays and pointers in c . One of the main things that confuse me is how when you refer to the name of an array, it could be referring to the array, or as a pointer to the first element, as well as a few other things. in order to better display where my trouble understanding is coming from, I'll display a few lines of code, as well as the conclusion that I've made from each one.
let's say that I have
int vals[] = {1,50,3,28,32,500};
int* valptr = vals;
Because vals is a pointer to the first value of the array, then that means that valptr, should equal vals as a whole, since I'm just setting a pointer equal to a pointer, like 1=1.
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
cout<<valptr<<endl;
the code above all prints out the same value, leading me to conclude two things, one that valptr and vals are equal, and can be treated in the same way, as well as the fact that, for some reason, adding & and * to vals doesn't seem to refer to anything different, meaning that using them in this way, is useless, since they all refer to the same value.
cout<<valptr[1]<<endl;//outputs 50
cout<<vals[1]<<endl;//outputs 50
cout<<*vals<<endl;//outputs 1
cout<<*valptr<<endl;//outputs 1
the code above furthers the mindset to me that valptr and vals are the same, seeing as whenever I do something to vals, and do the same thing to valptr, they both yield the same result
cout<<*(&valptr 1)-valptr<<endl;
cout<<endl;
cout<< *(&vals 1) -vals<<endl;
Now that we have established what I know, or the misconceptions that I may have, now we move on to the two main problems that I have, which we'll go over now.
The first confusion I have is with cout<< *(&vals 1) -vals<<endl;
I know that this outputs the size of the array, and the general concept on how it works, but I'm confused on several parts.
As shown earlier, if
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
all print out the same value, the why do I need the * and & in cout<< *(&vals 1) -vals<<endl;
I know that if I do vals 1
it just refers to the address of the next element on the array, meaning that *(vals 1)
returns 50.
This brings me to my first question: Why does the & in *(&vals 1)
refer to the next address out the array? why is it not the same output as (vals 1)
in the way that *(&vals)
and (vals)
have the same output?
Now to my second question. We know thatcout<< *(&vals 1) -vals<<endl;
is a valid statement, successfully printing the size of the array. However, as I stated earlier, in every other instance, valptr
could be substituted for vals
interchangeably. However, in the instance of writingcout<<*(&valptr 1)-valptr<<endl;
I get 0 returned, instead of the expected value of 6. How can something that was proven to be interchangeable before, no longer be interchangeable in this instance?
I appreciate any help that anyone reading this can give me
CodePudding user response:
Arrays and pointers are two different types in C that have enough similarities between them to create confusion if they are not understood properly. The fact that pointers are one of the most difficult concepts for beginners to grasp doesn't help either.
So I fell a quick crash course is needed.
Crash course
Arrays, easy
int a[3] = {2, 3, 4};
This creates an array named a
that contains 3 elements.
Arrays have defined the array subscript operator:
a[i]
evaluates to the i
'th element of the array.
Pointers, easy
int val = 24;
int* p = &val;
p
is a pointer pointing to the address of the object val
.
Pointers have the indirection (dereference) operator defined:
*p
evaluates to the value of the object pointed by p
.
Pointers, acting like arrays
Pointers give you the address of an object in memory. It can be a "standalone object" like in the example above, or it can be an object that is part of an array. Neither the pointer type nor the pointer value can tell you which one it is. Just the programmer. That's why
Pointers also have the array subscript operator defined:
p[i]
evaluates to the i
th element to the "right" of the object pointed by p
. This assumes that the object pointer by p
is part of an array (except in p[0]
where it doesn't need to be part of an array).
Note that p[0]
is equivalent to (the exact same as) *p
.
Arrays, acting like pointers
In most contexts array names decay to a pointer to the first element in the array. That is why many beginners think that arrays and pointers are the same thing. In fact they are not. They are different types.
Back to your questions
Because vals is a pointer to the first value of the array
No, it's not.
... then that means that valptr, should equal vals as a whole, since I'm just setting a pointer equal to a pointer, like 1=1.
Because the premise is false the rest of the sentence is also false.
valptr and vals are equal
No they are not.
can be treated in the same way
Most of the times yes, because of the array to pointer decay. However that is not always the case. E.g. as an expression for sizeof
and operand of &
(address of) operator.
Why does the & in
*(&vals 1)
refer to the next address out the array?
&vals
this is one of the few situation when vals
doesn't decay to a pointer. &vals
is the address of the array and is of type int (*)[6]
(pointer to array of 6 ints). That's why &vals 1
is the address of an hypothetical another array just to the right of the array vals
.
How can something that was proven to be interchangeable before, no longer be interchangeable in this instance?
Simply that's the language. In most cases the name of the array decays to a pointer to the first element of the array. Except in a few situations that I've mentioned.
More crash course
A pointer to the array is not the same thing as a pointer to the first element of the array. Taking the address of the array is one of the few instances where the array name doesn't decay to a pointer to its first element.
So &a
is a pointer to the array, not a pointer to the first element of the array. Both the array and the first element of the array start at the same address so the values of the two (&a
and &a[0]
) are the same, but their types are different and that matters when you apply the dereference or array subscript operator to them:
Expression | Expression type | Dereference / array subscript expresison |
Dereference / array subscript type |
---|---|---|---|
a |
int[3] |
*a / a[i] |
int |
&a |
int (*) [3] (pointer to array) |
*&a / &a[i] |
int[3] |
&a[0] |
int * |
*&a[0] / (&a[0])[i] |
int |