returns 指向数组的指针的 C 函数语法正确吗?

C function that returns a pointer to an array correct syntax?

在 C 中,您可以像这样声明一个指向数组的变量:

int int_arr[4] = {1,2,3,4};
int (*ptr_to_arr)[4] = &int_arr;

尽管实际上它与声明一个指向 int 的指针是一样的:

int *ptr_to_arr2 = int_arr;

但在句法上有所不同。

现在,returns 这样一个指向数组(例如 int)的指针的函数会是什么样子?

int 的声明是 int foo;

4 int 数组的声明是 int foo[4];.

一个指向4int数组的指针的声明是int (*foo)[4];.

返回指向 4 int 数组指针的函数的声明是 int (*foo())[4];()可以填写参数声明。

在这种情况下,typedef关键字可以使事情变得很多clearer/simpler:

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;
}

注意:正如评论和 , using a typedef to hide/bury a pointer is a practice that is frowned-upon by (most of) the professional C programming community – and for very good reasons. There is a good discussion about it here.

中所指出的

但是,尽管在您的情况下,您没有定义 actual 函数指针(这是大多数程序员会接受的 'rule' 的例外) ,您 定义复杂(即难以阅读)函数 return 类型。链接 post 末尾的讨论深入探讨了“太复杂”的问题,这就是我用来证明在像您这样的情况下使用 typedef 的理由。但是,如果你要选择这条路,那就要小心了。

如前所述,正确的语法是 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.

    中备受批评的类型系统
  • 稍微明智的work-around是通过其中一个参数return数组。这也不是很漂亮,但至少更容易阅读,因为奇怪的语法集中在一个参数上:

    void foo (int(**result)[4])
    {
      ...
      *result = &arr;
    }
    

    即:指向 int[4] 的 pointer-to-array 的指针。

  • 如果有人准备将类型安全抛出 window,那么 void* foo (void) 当然可以解决所有这些问题……但会产生新的问题。非常容易阅读,但现在的问题是类型安全和函数实际 return 的不确定性。也不好


那么,如果这些版本都有问题怎么办?有一些非常明智的方法。

好的解决方案:

  • 将分配留给调用者。这是 迄今为止 最好的方法,如果可以的话。您的函数将变为 void foo (int arr[4]); 可读且类型安全。

  • 老派 C。只是 return 指向数组中第一项的指针,并单独传递大小。这可能会或可能不会被接受,具体情况视情况而定。

  • 将其包装在结构中。例如,这可能是一些通用数组类型的合理实现:

    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;
    }