在C中,您可以声明一个指向数组的变量,如下所示:
int int_arr[4] = {1,2,3,4};
int (*ptr_to_arr)[4] = &int_arr;
尽管实际上它与声明指向int:的指针是一样的
int *ptr_to_arr2 = int_arr;
但从语法上来说,它是不同的。
现在,一个函数会是什么样子,它返回这样一个指向数组(例如int(的指针?
int
的声明就是int foo;
。
4个int
的数组的声明就是int foo[4];
。
指向4个int
的数组的指针的声明是int (*foo)[4];
。
返回指向4个int
的数组的指针的函数的声明是int (*foo())[4];
。()
可以用参数声明来填充。
如前所述,正确的语法是int (*foo(void))[4];
,正如您所知,它很难阅读。
有问题的解决方案:
-
使用C语言编写的语法。在我看来,这是你应该避免的,因为它非常难阅读,以至于完全无用。这在您的编码标准中应该是非法的,就像任何合理的编码标准强制使用
typedef
的函数指针一样。 -
哦,所以我们只是
typedef
,这就像使用函数指针时一样?人们可能会忍不住把这些黏糊糊的东西藏在typedef
后面,但这也有问题。这是因为数组和指针都是基本的"指针";构建块";在C语言中,使用程序员希望在处理它们时看到的特定语法。该语法的缺失表明了一个可以被寻址的对象;访问的左值";并像任何其他变量一样进行复制。将它们隐藏在typedef
后面最终可能会比原始语法造成更多的混乱。举个例子:
typedef int(*arr)[4]; ... arr a = create(); // calls malloc etc ... // somewhere later, lets make a hard copy! (or so we thought) arr b = a; ... cleanup(a); ... print(b); // mysterious crash here
所以这个";隐藏在typedef后面";系统在很大程度上依赖于我们命名类型
somethingptr
来指示它是一个指针。或者说。。。LPWORD
。。。就在那里;匈牙利符号";,备受批评的Windows API类型系统。 -
稍微明智一点的方法是通过其中一个参数返回数组。这也不太好看,但至少更容易阅读,因为奇怪的语法集中在一个参数上:
void foo (int(**result)[4]) { ... *result = &arr; }
即:指向指向
int[4]
数组的指针的指针。 -
如果一个人准备把类型安全抛出窗外,那么
void* foo (void)
当然可以解决所有这些问题。。。但创造了新的。很容易阅读,但现在的问题是类型安全性和函数实际返回内容的不确定性。也不好。
那么,如果这些版本都有问题,该怎么办?有一些非常明智的方法。
好的解决方案:
-
将分配留给调用者。如果你有选择的话,这是迄今为止最好的方法。您的函数将变为
void foo (int arr[4]);
,它可读且类型安全。 -
老派C.只需返回一个指向数组中第一个项目的指针,然后分别传递大小。根据具体情况,这可能是可接受的,也可能是不可接受的。
-
将其包装在结构中。例如,这可能是一些通用数组类型的合理实现:
typedef struct { size_t size; int arr[]; } array_t; array_t* alloc (size_t items) { array_t* result = malloc(sizeof *result + sizeof(int[items])); return result; }
在这种情况下,typedef
关键字可以使事情变得更清晰/更简单:
int int_arr[4] = { 1,2,3,4 };
typedef int(*arrptr)[4]; // Define a pointer to an array of 4 ints ...
arrptr func(void) // ... and use that for the function return type
{
return &int_arr;
}
注意:正如评论和Lundin的精彩回答中所指出的,使用typedef
隐藏/隐藏指针是一种(大多数(专业C编程社区不赞成的做法,这是有充分理由的。这里有一个很好的讨论。
然而,尽管在您的情况下,您没有定义实际的函数指针(这是大多数程序员会接受的"规则"的例外(,但定义的是复杂(即难以读取(的函数返回类型。链接帖子末尾的讨论深入探讨了";太复杂了";问题,这就是我在像您这样的情况下使用typedef
的理由。但是,如果你应该选择这条路,那么就要谨慎行事。