文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

嗨,大家好,许久不见(很久没用C语言了?)

大概来说,在C语言中,我们可以使用下列方式得到一个数组arr的长度:

int n = sizeof(arr) / sizeof(arr[0]);

这里,我们先取得这个数组的字节长度,然后将它除以单个的数组元素的长度。

那么让我们抛开sizeof方法,让事情看起来酷酷的吧。

曾经考虑过 arr 和 &arr 之间有什么区别吗?

让我们先打印出这两个指针的内存地址一探究竟吧:
image

这里是输出:
image

我们可以看到,在输出中,arr 和 &arr 都指向同一个内存地址 0x244fdc4

现在,我们对这两个指针同时进行加1操作,然后再检查它们的内存地址。

第 1 段(可获 1.34 积分)

以下是检查 arr + 1 和 &arr + 1 的内存地址的代码:

image

这是输出:

image

我们发现:

(arr + 1) 指向地址 0x244fdc8, 它跟指向地址 0x244fdc4的 arr 相差了4 字节远。
因为一个int变量占用了4 字节,所以 (arr + 1) 指向了这个数组的第二个元素。

(&arr + 1) 指向地址 0x244fdd8, 它跟指向地址 0x244fdc4的 arr 相差了20字节远。
(0x244fdd8 - 0x244fdc4 = 14,用16进制表示的,转换为十进制是20)

再考虑下int变量的大小, (&arr + 1) 就是距离这个数组起始位置5个int型变量大小远了。5 正好也是这个数组的长度。
所以, (&arr + 1) 指向的就是这个数组最后位置的内存地址。

第 2 段(可获 1.46 积分)

因此,我们可以推断出,虽然 arr 和 &arr 指向了同一个地址,但是他们在类型是不同的。

arr 的类型是 int *,而 &arr 的类型则是 int (*)[size]

&arr 指向的是整个数组而 arr 则指向的是整个数组的第一个元素。

image

这样就给我们带来了有用的东西——数组的长度。


(&arr + 1) 是这个数组的末尾的地址,而 arr 则是 整个数组第一个元素的地址。
将后者减去前者就能得到整个数组的长度。

int n = *(&arr + 1) - arr;

我们可以使用数组索引来简化一下(因为x[1] == *(x+1)),就变成了这样:

第 3 段(可获 1.33 积分)
int n = (&arr)[1] - arr;

顺便说一下:
这只对数组有效,可对指针是无效的(比如用字符 *str  声明一个字符串)。

void reverseStr(char *str){ 
  //wrong
  int strlength = (&str)[1] - str;
}

在这种情况下,&str 是一个指向指针str的指针。要记住,在C语言中,数组可不是指针。

后话:

我想引用一下我在reddit/SO上发现的一个关于同样话题的问答:

: 访问一个数组之后的第一个地址看起来似乎是种不可预料的行为。比如说:如果你的数组位于一块地址空间的末尾,而引用的地址会导致溢出,因此你的结果大小可能就是未知的了。那么你怎么才能访问 `(&arr)[1]` ?

: C不允许访问位于数组末尾的内存地址。但是,是允许一个指针去指向数组末尾端的那个元素的。这个区别是很重要的。

第 4 段(可获 1.65 积分)

文章评论

阿星
这篇文章解决了我一个心中疑问。