问题
It's fairly common knowledge that if you access an element of an array as arr[i]
in C that you can also access the element as i[arr]
, because these just boil down to *(arr + i)
and addition is commutative. My question is why this works for data types larger than char
, because sizeof(char)
is 1, and to me this should advance the pointer by just one char.
Perhaps this example makes it clearer:
#include <string.h>
#include <stdio.h>
struct large { char data[1024]; };
int main( int argc, char * argv[] )
{
struct large arr[4];
memset( arr, 0, sizeof( arr ) );
printf( "%lu\n", sizeof( arr ) ); // prints 4096
strcpy( arr[0].data, "should not be accessed (and is not)" );
strcpy( arr[1].data, "Hello world!" );
printf( "%s, %s, %s\n", arr[1].data, 1[arr].data, (*(arr+1)).data );
// prints Hello world!, Hello world!, Hello world!
// I expected `hold not be accessed (and is not)' for #3 at least
return 0;
}
So why does adding one to the array pointer advance it by sizeof( struct large )
?
回答1:
In C, pointer arithmetic is defined so that writing
ptr + k
does not advance the pointer by k bytes, but by k objects. Thus if you have a pointer to an integer array and writing
*(myIntArrayPointer + 3)
You are dereferencing a pointer to the element at index 3 in the array, not the integer that starts three bytes past the start of the object.
Similarly, if you subtract two pointers, you get the logical number of elements in-between them, not the total number of bytes. Thus writing
(myIntArrayPointer + 3) - myIntArrayPointer
yields the value 3, even though there are 3 * sizeof(int)
bytes in-between them.
Hope this helps!
回答2:
That's pointer arithmetic. When you write
some_pointer + i
it is compiled as
some_pointer + (i * sizeof(*my_pointer))
(i
is an int
for that matter :) )
回答3:
This sort of question can always be answered by reading the C spec. Try it!
§6.5.6 Additive Operators, paragraph 8:
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.
回答4:
The array/pointer is typed. The compiler knows how big the "thing" is, in this case your struct.
And C is just defined that way; advancing a pointer by "one" will go to the next thing in the array. The compiler knows how far to go for that. This applies to any of the related and equivalent syntaxes:
*(arr + i)
arr[i]
i[arr]
for any type that the compiler knows about.
This is called "pointer arithmetic", and it has at least one more fun property: if you have two pointers to items in an array, you can subtract them to get the count of items between them, in objects (i.e. not bytes).
回答5:
arr is declared as the array of 4 structures with each structure comprising of a char array of 1024 chars.
arr is resolved as the pointer to the first element to this array of structures. When you increment arr by 1, this new pointer, will skip one whole structure ( the type to which it points ) and then points to the next element in the array.
It all boils down to the compiler knowing the type to which a pointer points to, and then if you increment the array, it will point to the next element of the similar type in a contiguous memory location.
In this case if base address of the array is XYZ, then arr+ i = XYZ + i* sizeof(arr)/sizeof(struct large)
来源:https://stackoverflow.com/questions/7181504/why-does-iarr-work-as-well-as-arri-in-c-with-larger-data-types