a, &a, *a, a[0], &a[0] 和 &a[0][0] 是相同的指针吗? [英] Are a, &a, *a, a[0], &a[0] and &a[0][0] identical pointers?

查看:38
本文介绍了a, &a, *a, a[0], &a[0] 和 &a[0][0] 是相同的指针吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 C 程序:

#include <stdio.h>

int main(){
    int a[2][2] = {1, 2, 3, 4};
    printf("a:%p, &a:%p, *a:%p \n", a, &a, *a);
    printf("a[0]:%p, &a[0]:%p \n", a[0], &a[0]);
    printf("&a[0][0]:%p \n", &a[0][0]);
    return 0;
}

它给出以下输出:

a:0028FEAC, &a:0028FEAC, *a:0028FEAC
a[0]:0028FEAC, &a[0]:0028FEAC
&a[0][0]:0028FEAC

我不明白为什么 &aa*a - 都是相同的.a[0]&a[0]&a[0][0] 也是如此.

I am not able to understand why are &a, a, *a - all identical. The same for a[0], &a[0] and &a[0][0].

多亏了这些答案,我才明白为什么这些值是相等的.这行来自 Kernighan & 的书里奇竟然是我问题的关键:

Thanks to the answers, I've understood the reason why these values are coming out to be equal. This line from the book by Kernighan & Ritchie turned out to be the key to my question:

 the name of an array is a synonym for the location of the initial element.

这样,我们得到

a = &a[0], and

a[0] = &a[0][0](将a视为数组数组)

a[0] = &a[0][0] (considering a as an array of arrays)

直觉上,现在输出背后的原因很清楚.但是,考虑到指针是如何在 C 中实现的,我无法理解 a&a 是如何相等的.我假设内存中有一个变量 a 指向数组(并且这个数组内存块的起始地址将是这个变量 a 的值).

Intuitively, now the reason is clear behind the output. But, considering how pointers are implemented in C, I can't understand how a and &a are equal. I am assuming that there is a variable a in memory which points to the array(and the starting address of this array-memory-block would be the value of this variable a).

但是,当我们执行&a 时,这是否意味着获取存储变量a 的内存位置的地址?那么为什么这些值相等?

But, when we do &a, doesn't that mean taking the address of the memory location where the variable a was stored? Why are these values equal then?

推荐答案

它们不是相同的指针.它们是不同类型的指针,都指向相同的内存位置.相同的值(有点),不同的类型.

They're not identical pointers. They're pointers of distinct types that all point to the same memory location. Same value (sort of), different types.

C 中的二维数组只不过是数组的数组.

A 2-dimensional array in C is nothing more or less than an array of arrays.

对象a的类型为int[2][2],或int的二元数组的二元数组.

The object a is of type int[2][2], or 2-element array of 2-element array of int.

在大多数但不是所有上下文中,任何数组类型的表达式都隐式转换为(衰减"为)指向数组对象第一个元素的指针.所以表达式 a,除非它是一元&sizeof 的操作数,否则类型为int(*)[2],等价于 &a[0] (或者 &(a[0]) 如果更清楚的话).它成为指向二维数组第 0 行的指针.重要的是要记住,这是一个指针(或等效的地址),而不是一个指针对象;这里没有指针对象,除非你显式地创建.

Any expression of array type is, in most but not all contexts, implicitly converted to ("decays" to) a pointer to the array object's first element. So the expression a, unless it's the operand of unary & or sizeof, is of type int(*)[2], and is equivalent to &a[0] (or &(a[0]) if that's clearer). It becomes a pointer to row 0 of the 2-dimensional array. It's important to remember that this is a pointer value (or equivalently an address), not a pointer object; there is no pointer object here unless you explicitly create one.

所以看看你问的几个表达:

So looking at the several expressions you asked about:

  • &a 是整个数组对象的地址;它是一个 int(*)[2][2] 类型的指针表达式.
  • a 是数组的名称.如上所述,它衰减"到指向数组对象第一个元素(行)的指针.这是一个 int(*)[2] 类型的指针表达式.
  • *a 取消引用指针表达式a.由于 a(衰减后)是一个指向 2 个 int 数组的指针,*a 是一个包含 2 个 int 的数组 s.由于这是一个数组类型,它会衰减(在大多数但不是所有上下文中)指向数组对象的第一个元素的指针.所以它的类型是int*.*a 等价于 &a[0][0].
  • &a[0] 是数组对象的第一(第0)行的地址.它的类型是 int(*)[2].a[0] 是一个数组对象;它不会衰减为指针,因为它是一元 & 的直接操作数.
  • &a[0][0] 是数组对象第 0 行第 0 元素的地址.它的类型是 int*.
  • &a is the address of the entire array object; it's a pointer expression of type int(*)[2][2].
  • a is the name of the array. As discussed above, it "decays" to a pointer to the first element (row) of the array object. It's a pointer expression of type int(*)[2].
  • *a dereferences the pointer expression a. Since a (after it decays) is a pointer to an array of 2 ints, *a is an array of 2 ints. Since that's an array type, it decays (in most but not all contexts) to a pointer to the first element of the array object. So it's of type int*. *a is equivalent to &a[0][0].
  • &a[0] is the address of the first (0th) row of the array object. It's of type int(*)[2]. a[0] is an array object; it doesn't decay to a pointer because it's the direct operand of unary &.
  • &a[0][0] is the address of element 0 of row 0 of the array object. It's of type int*.

所有这些指针表达式都指向内存中的同一位置.该位置是数组对象a的开始;它也是数组对象 a[0]int 对象 a[0][0] 的开始.

All of these pointer expressions refer to the same location in memory. That location is the beginning of the array object a; it's also the beginning of the array object a[0] and of the int object a[0][0].

打印指针值的正确方法是使用"%p"格式将指针值转换为void*:

The correct way to print a pointer value is to use the "%p" format and to convert the pointer value to void*:

printf("&a = %p\n", (void*)&a);
printf("a  = %p\n", (void*)a);
printf("*a = %p\n", (void*)*a);
/* and so forth */

这种到 void* 的转换会产生一个原始"地址,该地址仅指定内存中的一个位置,而不是该位置的对象类型.因此,如果您有多个不同类型的指针指向从同一内存位置开始的对象,将它们全部转换为 void* 会产生相同的值.

This conversion to void* yields a "raw" address that specifies only a location in memory, not what type of object is at that location. So if you have multiple pointers of different types that point to objects that begin at the same memory location, converting them all to void* yields the same value.

(我已经掩盖了 [] 索引运算符的内部工作原理.表达式 x[y] 根据定义等同于 *(x+y),其中 x 是一个指针(可能是数组隐式转换的结果),y 是一个整数.反之亦然,但是这很丑陋;arr[0]0[arr] 是等价的,但只有在您编写故意混淆的代码时才有用.如果我们考虑到这种等价性,它用一段左右的时间来描述 a[0][0] 的意思,这个答案可能已经太长了.)

(I've glossed over the inner workings of the [] indexing operator. The expression x[y] is by definition equivalent to *(x+y), where x is a pointer (possibly the result of the implicit conversion of an array) and y is an integer. Or vice versa, but that's ugly; arr[0] and 0[arr] are equivalent, but that's useful only if you're writing deliberately obfuscated code. If we account for that equivalence, it takes a paragraph or so to describe what a[0][0] means, and this answer is probably already too long.)

为了完整起见,将数组类型的表达式隐式转换为指向数组第一个元素的指针的三个上下文是:

For the sake of completeness the three contexts in which an expression of array type is not implicitly converted to a pointer to the array's first element are:

  • 当它是一元&的操作数时,所以&arr产生整个数组对象的地址;
  • 当它是sizeof 的操作数时,所以sizeof arr 产生数组对象的字节大小,而不是指针的大小;和
  • 当它是用于初始化数组(子)对象的初始化程序中的字符串文字时,因此 char s[6] = "hello"; 将数组值复制到 s 而不是用指针值无意义地初始化数组对象.最后一个例外不适用于您询问的代码.
  • When it's the operand of unary &, so &arr yields the address of the entire array object;
  • When it's the operand of sizeof, so sizeof arr yields the size in bytes of the array object, not the size of a pointer; and
  • When it's a string literal in an initializer used to initialize an array (sub-)object, so char s[6] = "hello"; copies the array value into s rather than nonsensically initializing an array object with a pointer value. This last exception doesn't apply to the code you're asking about.

(N1570 草案2011 ISO C 标准错误地指出 _Alignof 是第四个异常;这是不正确的,因为 _Alignof 只能应用于带括号的类型名称,而不能应用于表达式.错误在最终的 C11 标准中更正了.)

(The N1570 draft of the 2011 ISO C standard incorrectly states that _Alignof is a fourth exception; this is incorrect, since _Alignof can only be applied to a parenthesized type name, not to a expression. The error is corrected in the final C11 standard.)

推荐阅读:comp.lang.c 常见问题解答的第 6 部分.

Recommended reading: Section 6 of the comp.lang.c FAQ.

这篇关于a, &amp;a, *a, a[0], &amp;a[0] 和 &amp;a[0][0] 是相同的指针吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆