为什么我和C中的arr 一样有更大的数据类型?
众所周知,如果你在C中以arr[i]
访问数组元素,你也可以像i[arr]
一样访问元素,因为这些只是归结为*(arr + i)
并且加法是可交换的。 我的问题是为什么这适用于大于char
数据类型,因为sizeof(char)
是1,对我来说这应该只需要一个char来推进指针。
也许这个例子让它更清晰:
#include #include 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 )
推进呢?
在C中,定义指针算法以便写入
ptr + k
不是将指针推进k 个字节 ,而是推进k 个 对象 。 因此,如果你有一个指向整数数组的指针并写入
*(myIntArrayPointer + 3)
您正在取消引用指向数组中索引3处的元素的指针,而不是从对象开始处开始三个字节的整数。
类似地,如果您减去两个指针,则会获得它们之间的逻辑元素数,而不是总字节数。 这样写作
(myIntArrayPointer + 3) - myIntArrayPointer
产生值3,即使它们之间有3 * sizeof(int)
字节。
希望这可以帮助!
这是指针算术 。 当你写作
some_pointer + i
它编译为
some_pointer + (i * sizeof(*my_pointer))
( i
是这个问题的int
:))
通过阅读C规范, 总能回答这类问题。 试试吧!
§6.5.6加法运算符,第8段:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。
键入数组/指针。 编译器知道“事物”有多大,在这种情况下你的结构。
而C就是这样定义的; 通过“一”推进指针将转到数组中的下一个事物。 编译器知道要走多远。 这适用于任何相关和等效的语法:
*(arr + i) arr[i] i[arr]
对于编译器知道的任何类型。
这称为“指针算术”,它至少有一个有趣的属性:如果你有两个指向数组中项目的指针,你可以减去它们以获得它们之间的项目数,即对象(即非字节)。
arr被声明为4个结构的数组,每个结构包含1024个字符的char数组。
arr被解析为指向此结构数组的第一个元素的指针。 当你将arr增加1时,这个新指针将跳过一个整体结构(它指向的类型),然后指向数组中的下一个元素。
这一切都归结为编译器知道指针所指向的类型,然后如果递增数组,它将指向连续内存位置中相似类型的下一个元素。
在这种情况下,如果数组的基址是XYZ,则arr + i = XYZ + i * sizeof(arr)/ sizeof(struct large)