关于 C 语言中解引用运算符 ("*") 的困惑
Confusion about dereference operator ("*") in C
据我所知,解引用运算符 *
returns 存储在指针地址中的值。我感到困惑的是运算符与数组指针一起使用时的行为。例如,
int a[4][2];
然后a
被内部转换为2个整数的4个元素数组的第一个元素的指针。那么*a
return是哪个值呢?我真的很困惑!
a
的类型是int[4][2]
,所以*a
(或等效的a[0]
)的类型是int[2]
。
与a[0][0]
不相同。如果你这样做:
int a[4][2];
printf("%d\n",*a);
编译器会告诉你:
warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘int *’
由于数组(在本例中为 int [2]
类型之一)被传递给函数,它会衰减为指向此上下文中第一个元素的指针。
如果另一方面您有 **a
,则相当于 a[0][0]
并且类型为 int
.
这个:
int a[4][2];
定义了a
一个包含4个元素的数组,每个元素都是一个包含2个int
个元素的数组。 (二维数组不过是数组的数组。)
在大多数上下文中,数组表达式隐式转换为指向数组对象的初始(第零个)元素的指针。 (请注意假设有一个数组 object;这引起了一些焦虑,但它与这里无关。)
数组表达式不转换为指针的情况是:
- 当是
sizeof
的操作数时;
- 当为一元操作数时
&
;和
- 当它是用于初始化数组对象的初始化程序中的字符串文字时。
(特定于编译器的扩展,如 gcc 的 typeof
可能会产生更多异常。)
所以在表达式*a
中,子表达式a
(int[4][2]
类型)被隐式转换为int(*)[2]
类型的指针(指向数组的指针2 int
秒)。应用一元 *
取消引用该指针,为我们提供类型 int[2]
.
的表达式
但我们还没有完全。 *a
也是一个数组类型的表达式,也就是说,根据使用的不同,它可能又会被转为指针,这次是[=24]类型=].
如果我们写sizeof *a
,子表达式a
从int[4][2]
转换为int(*)[2]
,但是子表达式*a
是 not 从 int[2]
转换为 int*
,因此表达式产生 int[2]
.
类型的大小
如果我们写 **a
,转换 会 发生。 *a
是int[2]
类型,转换为int*
;解引用产生 int
.
类型的表达式
请注意,尽管我们可以合法地引用 **a
,使用两个指针取消引用操作,但没有指针 对象 。 a
是一个数组对象,完全由8个int
对象组成。隐式转换产生指针 values.
隐式数组到指针的转换规则在 N1570 节 6.3.2.1 第 3 段。(该段错误地将 _Alignof
作为第四个例外,但 _Alignof
不能应用于表达式。已发布的 C11 标准更正了错误。)
推荐阅读:comp.lang.c FAQ.
的第6节
据我所知,解引用运算符 *
returns 存储在指针地址中的值。我感到困惑的是运算符与数组指针一起使用时的行为。例如,
int a[4][2];
然后a
被内部转换为2个整数的4个元素数组的第一个元素的指针。那么*a
return是哪个值呢?我真的很困惑!
a
的类型是int[4][2]
,所以*a
(或等效的a[0]
)的类型是int[2]
。
与a[0][0]
不相同。如果你这样做:
int a[4][2];
printf("%d\n",*a);
编译器会告诉你:
warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘int *’
由于数组(在本例中为 int [2]
类型之一)被传递给函数,它会衰减为指向此上下文中第一个元素的指针。
如果另一方面您有 **a
,则相当于 a[0][0]
并且类型为 int
.
这个:
int a[4][2];
定义了a
一个包含4个元素的数组,每个元素都是一个包含2个int
个元素的数组。 (二维数组不过是数组的数组。)
在大多数上下文中,数组表达式隐式转换为指向数组对象的初始(第零个)元素的指针。 (请注意假设有一个数组 object;这引起了一些焦虑,但它与这里无关。)
数组表达式不转换为指针的情况是:
- 当是
sizeof
的操作数时; - 当为一元操作数时
&
;和 - 当它是用于初始化数组对象的初始化程序中的字符串文字时。
(特定于编译器的扩展,如 gcc 的 typeof
可能会产生更多异常。)
所以在表达式*a
中,子表达式a
(int[4][2]
类型)被隐式转换为int(*)[2]
类型的指针(指向数组的指针2 int
秒)。应用一元 *
取消引用该指针,为我们提供类型 int[2]
.
但我们还没有完全。 *a
也是一个数组类型的表达式,也就是说,根据使用的不同,它可能又会被转为指针,这次是[=24]类型=].
如果我们写sizeof *a
,子表达式a
从int[4][2]
转换为int(*)[2]
,但是子表达式*a
是 not 从 int[2]
转换为 int*
,因此表达式产生 int[2]
.
如果我们写 **a
,转换 会 发生。 *a
是int[2]
类型,转换为int*
;解引用产生 int
.
请注意,尽管我们可以合法地引用 **a
,使用两个指针取消引用操作,但没有指针 对象 。 a
是一个数组对象,完全由8个int
对象组成。隐式转换产生指针 values.
隐式数组到指针的转换规则在 N1570 节 6.3.2.1 第 3 段。(该段错误地将 _Alignof
作为第四个例外,但 _Alignof
不能应用于表达式。已发布的 C11 标准更正了错误。)
推荐阅读:comp.lang.c FAQ.
的第6节