简体   繁体   中英

why can't a pointer-to-array-of-ints be assigned to a pointer-to-int?

in c primer plus, it tells me some assignment rules followed:

a pointer-to-array-of-ints can't be assigned to a pointer-to-int.

 int *pt; int a[3][2];
 pt=a; /* invalid */

a pointer-to-array-of-two-ints can't be assigned to pointer-to-array-of-three-ints.

 int (*pt)[3]; int a[3][2];
 pt=a; /* invalid */

frankly I am confused this explanation. Because though the above pointers are pointers to different objects, in memories, pointers are all stored as hexadecimal address in unsigned, which means they have the same storage forms. they are unified in 8 bits(64bit OS) or 4bits(32bit OS). So why do they can't assigned to each other in root cause? Because compilers prohibit these kinds of assignments?

A primary reason languages have types is to help programmers avoid making mistakes. Pointers to different types of things are treated as different types themselves. Rules like this catch many mistakes where a programmer might assign a pointer to the wrong thing.

An int , an array of two int , and an array of three int are different types of things, so pointers to them are different types of pointers, and the rules of C require the compiler to diagnose any attempt to assign one to the other. (This can be overridden by using a cast to explicitly convert the pointer, but that should be avoided until you have learned C rules about aliasing objects using different types.)

Most simply, to set int *pt to point to the first element of int a[3][2] , you can use pt = &a[0][0]; or pt = a[0]; . In the latter, since a is an array of three arrays of two int , a[0] is an array of two int . When used in an expression other than as the operand of sizeof or unary & 1 , it is automatically converted to a pointer to its first element, so it behaves the same as &a[0][0] .

Incidentally, the statements “… pointers are all stored as hexadecimal address in unsigned, which means they have the same storage forms. they are unified in 8 bits(64bit OS) or 4bits(32bit OS)” are not generally true. The C standard permits different types of pointers to have different representations. This is uncommon in modern C implementations but does exist.

Footnote

1 String literals used to initialize arrays of characters are also not converted to pointers.

Type matters for pointers, just like it matters for integers, floats, strings, etc. Pointer arithmetic is done in terms of the pointed-to type. Assume you have the following pointers and objects:

int i;
int *pi = &i

int arr[10];
int (*pa)[10] = &arr;

If the expression p evaluates to the address of i , then p + 1 evaluates to the address of the next int object following i . Similarly, if pa evaluates to the address of arr , then pa + 1 evaluates to the address of the next 10-element array of int following arr .

This is how array subscripting works - the expression a[i] is defined as *(a + i) - given a starting address a , offset i objects (not bytes!) from that address and dereference the result.

Pointers to different types are themselves different types, and like those other types, don't have to have the same size and representation:

6.2.5 Types
...
28 A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. 48) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.
48) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

C 2011 Online Draft

On most modern desktop and server systems (read: x86), pointer types are all the same size and representation, but that's a function of the implementation, not the language. An int * doesn't have to be the same size or have the same representation as an int (*)[3] .

So, this is why you can't assign a pointer of one type to another unless they are compatible types, or one of them is a void * , or you use an explicit cast:

int *p = (int *) &arr;

The pointer variable int (*pt)[3] is not compatible with the array int a[3][2] but the pointer variable int (*pt)[2] is compatible with the array.

At first glance to the new C programmer, the declaration int a[3][2]; might look like it is declaring a as an array of length 2 where each element is an array of length 3 of int , but the first glance would be deceiving in that case. The declaration int a[3][2]; is actually declaring a as an array of length 3 where each element is an array of length 2 of int . It can be read in pseudo-English with the dimensions stated in the same order they appear in the declaration as " declare a as array[3] of array[2] of int ". The "inner" dimensions appear to the right of the "outer" dimensions in multi-dimensional array declarations.

The declaration int (*p2)[2]; can be read in pseudo-English as " declare p2 as pointer to array[2] of int " and of course it follows that int (*p3)[3]; can be read as " declare p3 as pointer to array[3] of int ". Pointer types where the pointed-to types are array types of different length are not compatible with each other, so the type of p2 is not compatible with the type of p3 .

When, in an expression (except certain types of expressions), a multi-dimensional array decays to a pointer to its first element, it is the first dimension (the leftmost, or outermost dimension) that is eliminated during the decay, and all the remaining dimensions (if any) are preserved in the pointed-to type. For example, an array of type T [A][B][C] (" array[A] of array[B] of array[C] of T ") will decay to a pointer of type T (*)[B][C] (" pointer to array[B] of array[C] of T ").

In the expressions p2 = a; and p3 = a; , a decays to &a[0] which is of type int (*)[2] (" pointer to array[2] of int "). That pointer type is compatible with that of p2 but is not compatible with that of p3 . The assignment expression p2 = a; is OK, but the assignment expression p3 = a; involves an assignment between incompatible pointer types.

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