我没有发现指针理论特别麻烦,但我偶尔会被一些符号弄乱。在以下示例中,有人可以解释行p = (int*) a
的工作原理。我对代码的解释表明,这一行只是将第一个数组的第一个元素的地址存储在指针p中,这样printf("%u", *p)
就会产生5
。如果是这种情况,这一行只是一种更间接的写作方式p = a[0]
?
int main()
{
int a[][4] = {
5, 7, 5, 9,
4, 6, 3, 1,
2, 9, 0, 6
};
int *p; // create an integer pointer
int (*q)[4]; // create a pointer to a four-element integer array
p = (int*)a; // ?
q = a;
printf("%u %u\n", p, q);
p++;
q++;
printf("%u %u\n", p, q);
return 0;
}
答案 0 :(得分:8)
当在值上下文中使用时,表达式a
确实将评估为“数组a
的第一个元素的地址” - a[0]
的地址 - 正如您正确理解的那样它。
但请注意,数组a
实际上就是我们所说的 2D 数组。它是一个数组数组。数组a
的第一个元素本身就是一个数组:类型为int [4]
的数组。因此,考虑到上述情况,表达式a
在值上下文中使用时,等同于表达式&a[0]
,它是类型为int (*)[4]
的指针,在概念上指向整个 1D数组a[0]
。
出于这个原因,尝试做
p = a;
将导致编译器发出诊断消息。将int (*)[4]
值分配给int *
指针对象是违法的。这些类型不兼容。为了抑制此诊断消息,所讨论的代码使用显式转换
p = (int *) a;
这有力地将上述int (*)[4]
指针值推入p
。在典型的实现中,这保留了原始指针的数值,仅执行概念类型转换。
尝试访问*p
的值通常会产生a[0][0]
的值,因为数字整个a
的地址与a[0]
的地址,与a[0][0]
的地址相同。上面的代码利用了这个数字标识,同时使用显式转换来解决类型不兼容问题。
答案 1 :(得分:7)
我对代码的解释表明,这一行只是将第一个数组的第一个元素的地址存储在指针p中
正确。
如果是这种情况,这一行只是一种更间接的写作方式
p = a[0]
?
不,不是。 “这条线只存储第一个元素的地址” - 它相当类似于
p = &a[0];
但上述陈述并不完全正确,因为&a[0]
的类型为int (*)[4]
。没有强制转换的正确分配可能类似于
p = &a[0][0];
使用-Wall
打开时编译各种声明并偶尔发现错误/警告:)
答案 2 :(得分:2)
要扩展H2CO3的答案,请记住在大多数情况下, array 类型的表达式将转换为 pointer 类型的表达式,并且表达式的值将是数组第一个元素的地址。
表达式a
的类型是“int
的4元素数组的3元素数组”。除非它是sizeof
,_Alignof
或一元&
运算符的操作数,否则a
将转换为到类型为“的表达式”指向int
“(int (*)[4]
)的4元素数组的指针,其值将是a[0]
的地址。问题是类型int (*)[4]
的值无法分配给int *
类型的变量;类型不是兼容的,因此我们需要将表达式a
的结果转换为int *
。
这是有效的,因为数组的地址和数组的第一个元素的地址是相同的 - 表达式a
,&a
,a[0]
,&a[0]
和&a[0][0]
都生成相同的值,它们只有不同的类型(int (*)[4]
,int (*)[4][4]
,int *
,分别为int (*)[4]
和int *
。
答案 3 :(得分:0)
几乎。它与写p = &a[0][0]
类似。
答案 4 :(得分:-2)
a
是3
数组4
的数组int
。
a
的值是指向4
的数组int
的指针。该指针的值是数组开头的地址。
(int *) a
将指针转换为指向int
的指针。值不会改变,但类型不同。
请注意,要打印指针值,正确的规范为p
。