简体   繁体   中英

C - what is array name when not converted to pointer of its type?

So for a while I was confused about array names and pointers.

We declare int a[10]; And somewhere down the road also have a and &a .

So I get how the syntax works. a is the array name. When it is not used as an operand for sizeof & , etc., it will be converted or "decayed" so it returns a pointer to integer holding the address of the first element of the array.

If the array name is used as an operand for sizeof or & , its type is int (*)[10] . So I guess the type is different because that "decay" does not happen.

But I still do not understand how &a works. My understanding is that it is giving me the address of whatever it was before the "decay" happened .. So before the "decay" to pointer happened, then what is it and how does the compiler work with the "original" to evaluate &a ?

In comparison, if we declare int *p; and later have &p and p somewhere in the code...

In this case the pointer to integer p is given a separate pointer cell with its address and the value at that address will be whatever address we assign to it (or the garbage value at that address pre-assignment).

a does not get assigned a separate pointer cell in memory when it is declared int a[10] . I heard it is identified with an offset on the register %ebp . Then what is happening with the compiler when it evaluates &a ? The "decay" to a pointer to integer is not happening, there was no separate "pointer" in the first place. Then what does the compiler identify a as and what does it do when it sees that unary & operator is using the array name as an operand?

Given:

int a[10];

the object a is of type int[10] . The expression a , in most but not all contexts, "decays" to a pointer expression; the expression yields a value of type int* , equivalent to &a[0] .

But I still do not understand how &a works. My understanding is that it is giving me the address of whatever it was before the "decay" happened .. So before the "decay" to pointer happened, then what is it and how does the compiler work with the "original" to evaluate &a ?

That's not quite correct. In &a , the decay doesn't happen at all. a is of type "array of 10 int " ( int[10] ), so &a is of type "pointer to array of 10 int " ( int(*)[10] ).

There's nothing special about this. For any name foo of type some_type , the expression &foo is of type "pointer to some_type ". (What's confusing about it is that this is one of the rare cases where an array name doesn't behave strangely.)

It's best to think of the words "array" and "pointer" as adjectives rather than nouns. Thus we can have an array object, an array expression, an array type, and so forth -- but just "an array" is ambiguous.

This:

int a[10];

defines an array object named a (and allocates 4 * sizeof (int) bytes to hold it). No pointer object is created. You can create a pointer value by taking the address of the object, or of any element of it. This is no different than objects of any other type. Defining an object of type some_type doesn't create an object of type some_type* , but you can create a value of type some_type* by computing the address of the object.

Then what does the compiler identify a as and what does it do when it sees that unary & operator is using the array name as an operand?

The compiler identifies a as a 10-element integer array, and when it sees the & operator, it returns the address of that array.

Just like it would see int i = 3; as an integer, and &i as the address of that integer.

Concerning taking the address of an array: an array is an object in and of itself, so it has both a size and an address (though taking its address is seldom useful).

The conversion of an array to a pointer to its first element is a form of type coercion. It only happens if the alternative would be a compile error.

For instance, you can't compare an array to a pointer, so the array (implicitly) is coerced (cast) to an int* (to its first element) and then the pointer types are compared. In C you can compare any pointer types. C just doesn't care (though it will likely emit a warning).

This is actually comparing int* to int(*)[10] as far as types are concerned, as you said. These will necessary have the same address (regardless of typing) because arrays hold their data directly. So the address of an array will always be the address of its first element.

However, it's not an error to get the size of an array, so sizeof(a) gets the size of the entire array, as no coercion is needed to make this legal. So this is the same as sizeof(int[10]) .

Your other case sizeof(&a) is really sizeof(int(*)[10]) as you said.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM