now*_*wox 10 c arrays pointers language-lawyer
最近,我注意到,在C,有一个重要区别array,并&array以下声明:
char array[] = {4, 8, 15, 16, 23, 42};
Run Code Online (Sandbox Code Playgroud)
前者是一个指向 char 的指针,而后者是一个指向 6 个字符的数组的指针。另外值得注意的是,写作a[b]是*(a + b). 确实,您可以编写2[array]并根据标准完美运行。
所以我们可以利用这些信息来写:
char last_element = (&array)[1][-1];
Run Code Online (Sandbox Code Playgroud)
&array具有 6 个字符的大小,因此(&array)[1])是指向位于数组后面的字符的指针。通过查看,[-1]我正在访问最后一个元素。
有了这个,我可以例如交换整个数组:
void swap(char *a, char *b) { *a ^= *b; *b ^= *a; *a ^= *b; }
int main() {
char u[] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < sizeof(u) / 2; i++)
swap(&u[i], &(&u)[1][-i - 1]);
}
Run Code Online (Sandbox Code Playgroud)
这种最后访问数组的方法有缺陷吗?
Eri*_*hil 12
C 标准没有定义(&array)[1].
考虑&array + 1。这是由 C 标准定义的,原因有二:
&array是一个指向单个对象的指针(它本身就是一个数组,但指针算法是针对数组指针,而不是元素指针)。所以&array + 1是定义指针运算它指向刚刚超越结束array。
但是,根据下标运算符的定义,(&array)[1]是*(&array + 1)。虽然&array + 1定义了,但应用*到它时却没有。C 2018 6.5.6 8 明确告诉我们,关于指针运算的结果,“如果结果指向数组对象的最后一个元素,则不应将其用作*被评估的一元运算符的操作数。”
由于大多数编译器的设计方式,问题中的代码可能会根据您的需要移动数据。但是,这不是您应该依赖的行为。您可以使用 获得指向数组最后一个元素之外的良好指针char *End = array + sizeof array / sizeof *array;。然后你可以使用End[-1]来引用最后一个元素,End[-2]引用倒数第二个元素,依此类推。