首先,您的问题是指“typedef”而不是“typecast”。
在 C 中,指向 T 类型的指针可以指向 T 类型的对象:
int *pi;
int i;
pi = &i;
以上内容很容易理解。现在,让我们让它更复杂一些。您似乎知道数组和指针之间的区别(即,您知道数组不是指针,但有时它们的行为类似于它们)。所以,你应该能够理解:
int a[3];
int *pa = a;
但为了完整起见:在赋值中,名称a 等价于&a[0],即指向数组a 的第一个元素的指针。如果您不确定它的工作原理和原因,有很多答案可以准确解释数组的名称何时“衰减”为指针,何时没有:
我相信在 SO 上还有更多这样的问题和答案,我只是提到了一些我从搜索中找到的。
回到主题:当我们有:
int foo[2][3];
foo 的类型为“数组[2] 的数组[3] 的int”。这意味着foo[0] 是一个由 3 个ints 组成的数组,foo[1] 是一个由 3 个ints 组成的数组。
现在假设我们要声明一个指针,并将其分配给foo[0]。也就是说,我们想做:
/* declare p somehow */
p = foo[0];
上面的形式与int *pa = a; 行没有什么不同,因为a 和foo[0] 的类型是相同的。所以,我们需要int *p; 作为p 的声明。
现在,关于数组要记住的主要一点是,关于数组名称衰减为指向其第一个元素的指针的“规则”仅适用一次。如果您有一个数组的数组,那么在值上下文中,数组的名称不会衰减为“指向指针的指针”类型,而是“指向数组的指针”。回foo:
/* What should be the type of q? */
q = foo;
上面的名字foo是指向foo的第一个元素的指针,也就是说,我们可以把上面写成:
q = &foo[0];
foo[0] 的类型是“数组[3] of int”。所以我们需要q 是一个指向“数组[3] of int”的指针:
int (*q)[3];
q 周围的括号是必需的,因为 [] 在 C 中的绑定比 * 更紧密,所以 int *q[3] 将 q 声明为一个指针数组,我们想要一个指向数组的指针。从上面看,int *(q[3]) 等价于 int *q[3],即一个由 3 个指向 int 的指针组成的数组。
希望对您有所帮助。您还应该阅读 C for smarties: arrays and pointers 以获得关于此主题的非常好的教程。
关于一般的阅读声明:从“变量”的名称(如果有的话)开始“由内而外”地阅读它们。除非有一个 [] 在紧邻的右边,否则你尽可能向左走,并且你总是尊重括号。 cdecl应该可以帮到你:
$ cdecl
cdecl> declare p as pointer to array 3 of int
int (*p)[3]
cdecl> explain int (*p)[3]
declare p as pointer to array 3 of int
阅读
int (*a)[3];
a # "a is"
(* ) # parentheses, so precedence changes.
# "a pointer to"
[3] # "an array [3] of"
int ; # "int".
对于
int *a[3];
a # "a is"
[3] # "an array [3] of"
* # can't go right, so go left.
# "pointer to"
int ; # "int".
对于
char *(*(*a[])())()
a # "a is"
[] # "an array of"
* # "pointer to"
( )() # "function taking unspecified number of parameters"
(* ) # "and returning a pointer to"
() # "function"
char * # "returning pointer to char"
(来自c-faq question 1.21的示例。实际上,如果您正在阅读如此复杂的声明,则代码存在严重错误!)