Is an array's name a pointer in C? If not, what is the difference between an array's name and a pointer variable?
相关问题
- Multiple sockets for clients to connect to
- Do the Java Integer and Double objects have unnece
- What is the best way to do a search in a large fil
- How to get the maximum of more than 2 numbers in V
- Faster loop: foreach vs some (performance of jsper
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
An array declared like this
allocates memory for 10
int
s. You can't modifya
but you can do pointer arithmetic witha
.A pointer like this allocates memory for just the pointer
p
:It doesn't allocate any
int
s. You can modify it:and use array subscripts as you can with a:
I think this example sheds some light on the issue:
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
Even though
c
anda
"point" to the same memory, you can obtain address of thec
pointer, but you cannot obtain the address of thea
pointer.An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
a
contains space for seven integers, and you can put a value in one of them with an assignment, like this:Here is a pointer:
p
doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the arraya
, such as the first one:What can be confusing is that you can also write this:
This does not copy the contents of the array
a
into the pointerp
(whatever that would mean). Instead, the array namea
is converted to a pointer to its first element. So that assignment does the same as the previous one.Now you can use
p
in a similar way to an array:The reason that this works is that the array dereferencing operator in C,
[ ]
, is defined in terms of pointers.x[y]
means: start with the pointerx
, stepy
elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax,x[y]
can also be written as*(x+y)
.For this to work with a normal array, such as our
a
, the namea
ina[3]
must first be converted to a pointer (to the first element ina
). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the
sizeof
operator on an array. Ifa
was converted to a pointer in this context,sizeof a
would give the size of a pointer and not of the actual array, which would be rather useless, so in that casea
means the array itself.If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the
&
orsizeof
operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
what you get in memory is
The expression
a
refers to the entire array, but there's no objecta
separate from the array elements themselves. Thus,sizeof a
gives you the size (in bytes) of the entire array. The expression&a
gives you the address of the array, which is the same as the address of the first element. The difference between&a
and&a[0]
is the type of the result1 -int (*)[10]
in the first case andint *
in the second.Where things get weird is when you want to access individual elements - the expression
a[i]
is defined as the result of*(a + i)
- given an address valuea
, offseti
elements (not bytes) from that address and dereference the result.The problem is that
a
isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such asa
, which has typechar [10]
) and that expression isn't the operand of thesizeof
or unary&
operators, the type of that expression is converted ("decays") to a pointer type (char *
), and the value of the expression is the address of the first element of the array. Therefore, the expressiona
has the same type and value as the expression&a[0]
(and by extension, the expression*a
has the same type and value as the expressiona[0]
).C was derived from an earlier language called B, and in B
a
was a separate pointer object from the array elementsa[0]
,a[1]
, etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the
gets
function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.An array is a collection of secuential and contiguous elements in memory. In C an array's name is the index to the first element, and applying an offset you can access the rest of elements. An "index to the first element" is indeed a pointer to a memory direction.
The difference with pointer variables is that you cannot change the location the array's name is pointing to, so is similar to a const pointer (it's similar, not the same. See Mark's comment). But also that you don't need to dereference the array name to get the value if you use pointer aritmetic:
So the answer is kinda 'yes'.