10

众所周知,如果您像arr[i]在 C 中那样访问数组的元素,您也可以像访问该元素一样i[arr],因为这些只是归结为*(arr + i)并且加法是可交换的。我的问题是为什么这适用于大于char, 因为sizeof(char)是 1 的数据类型,对我来说这应该只将指针提前一个字符。

也许这个例子更清楚:

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

4

5 回答 5

11

在 C 中,定义了指针算术,以便编写

ptr + k

不将指针前移 k个字节,而是前移 k 个对象。因此,如果您有一个指向整数数组的指针并写入

*(myIntArrayPointer + 3)

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

同样,如果你减去两个指针,你会得到它们之间元素的逻辑数,而不是字节总数。这样写

(myIntArrayPointer + 3) - myIntArrayPointer

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

希望这可以帮助!

于 2011-08-24T20:01:14.247 回答
7

那是指针算术。当你写

some_pointer + i 

它被编译为

some_pointer + (i * sizeof(*my_pointer))

(对于那件事i来说是一个int:))

于 2011-08-24T20:01:57.120 回答
2

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

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

当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。

于 2011-08-24T20:03:59.897 回答
1

输入数组/指针。编译器知道“东西”有多大,在这种情况下是你的结构。

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

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

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

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

于 2011-08-24T19:59:43.830 回答
0

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

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

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

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

于 2011-08-24T20:06:50.527 回答