为什么我[arr]和C中的arr [i]一样有更大的数据类型?

时间:2011-08-24 19:59:00

标签: c arrays pointers pointer-arithmetic

众所周知,如果您在C中以arr[i]的形式访问数组元素,您也可以将该元素作为i[arr]来访问,因为这些元素只能归结为*(arr + i)和加法是可交换的。我的问题是为什么这适用于大于char的数据类型,因为sizeof(char)是1,而对我而言,这应该只用一个char来推进指针。

也许这个例子更清楚:

#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;

}

那么为什么在数组指针中添加一个按sizeof( struct large )推进呢?

5 个答案:

答案 0 :(得分:11)

在C中,定义指针算法以便写入

ptr + k

不会将指针推进k 字节,而是通过k 对象。因此,如果你有一个指向整数数组的指针并编写

*(myIntArrayPointer + 3)

您正在取消引用指向数组中索引3处元素的指针,而不是在对象开头之后开始三个字节的整数。

类似地,如果减去两个指针,则会获得它们之间的逻辑元素数,而不是总字节数。因此写作

(myIntArrayPointer + 3) - myIntArrayPointer

产生值3,即使它们之间有3 * sizeof(int)个字节。

希望这有帮助!

答案 1 :(得分:6)

那是pointer arithmetic。当你写

some_pointer + i 

编译为

some_pointer + (i * sizeof(*my_pointer))

i就此而言是int :))

答案 2 :(得分:1)

键入数组/指针。编译器知道“事物”的大小,在这种情况下是你的结构。

C就是这样定义的;通过“一”推进指针将转到数组中的下一个事物。编译器知道要走多远。这适用于任何相关和等效的语法:

*(arr + i)
arr[i]
i[arr]

对于编译器知道的任何类型。

这称为“指针算术”,它至少还有一个有趣的属性:如果你有两个指向数组中项目的指针,你可以减去它们以获得它们之间的项目数,在对象中(即不个字节)。

答案 3 :(得分:1)

通过阅读C规范可以总是回答这类问题。试试吧!

§6.5.6加法运算符,第8段:

  

添加或减去具有整数类型的表达式时   从指针开始,结果具有指针操作数的类型。如果   指针操作数指向数组对象的元素和数组   足够大,结果指向一个偏离的元素   原始元素使得下标的差异   结果和原始数组元素等于整数表达式。

答案 4 :(得分:0)

arr被声明为4个结构的数组,每个结构包含1024个字符的char数组。

arr被解析为指向此结构数组的第一个元素的指针。当你将arr增加1时,这个新指针将跳过一个整个结构(它指向的类型),然后指向数组中的下一个元素。

这一切都归结为编译器知道指针指向的类型,然后如果递增数组,它将指向连续内存位置中相似类型的下一个元素。

在这种情况下,如果数组的基址是XYZ,那么arr + i = XYZ + i * sizeof(arr)/ sizeof(struct large)