It's not entirely clear what you're trying to accomplish, so I'll cover more than one possibility.
First of all, a refresher on how to read and write complicated declarations in C:
Remember that () and [] have higher precedence than unary *, so *a[] is an array of pointers, while (*a)[] is a pointer to an array; similarly, *f() is a function returning a pointer, while (*f)() is a pointer to a function.
When you're trying to read a hairy declaration, start with the leftmost identifier and work your way out, remembering the rule above. Thus,
int (*(x)())[2];
reads as
x -- x
(x) -- x
(x)() -- is a function
*(x)() -- returning a pointer
(*(x)())[2] -- to a 2-element array
int (*(x)())[2] -- of int
In this case, the parens immediately surrounding x are redundant, and can be removed: int (*x())[2];.
Here's how such a function could be written and used:
int (*x())[2]
{
int (*arr)[2] = malloc(sizeof *arr); // alternately, you could simply write
return arr; // return malloc(sizeof (int [2]));
} // type of *arr == int [2]
int main(void)
{
int (*p)[2] = NULL; // alternately, you could write
... // int (*p)[2] = x();
p = x();
...
free(p);
}
Notice that the declarations of arr, p, and x() all look the same -- they all fit the pattern int (*_)[2];. THIS IS IMPORTANT. If you declare one thing as T (*p)[N] and another thing as T **q, then their types are different and may not be compatible. A pointer to an array of T is a different type than a pointer to a pointer to T.
If your goal is to create an array of pointers to functions returning int, then your types would look like int (*f[2])();, which reads as
f -- f
f[2] -- is a 2-element array
*f[2] -- of pointers
(*f[2])() -- to functions
int (*f[2])(); -- returning int
That would look something like the following:
int foo() {...}
int bar() {...}
int main(void)
{
int (*f[2])() = {foo, bar};
...
}
If you want a function that returns f, that's a little trickier. C functions cannot return array types; they can only return pointers to arrays, so your function declaration would be built up as
g -- g
g() -- is a function
*g() -- returning a pointer
(*g())[2] -- to a 2-element array
*(*g())[2] -- of pointers
(*(*g())[2])() -- to functions
int (*(*g())[2])() -- returning int
And such a beastie would be used something like this:
int foo() {...}
int bar() {...}
int (*(*g())[2])()
{
int (*(*f)[2])() = malloc(sizeof *f);
(*f)[0] = foo; // the type of the *expressions* foo and bar
(*f)[1] = bar; // is `int (*)()`, or pointer to function
return f; // returning int
}
int main(void)
{
int (*(*p)[2])();
int x, y;
...
p = g();
x = (*(*p)[0])();
y = (*(*p)[1])();
...
free(p);
...
}
Note that you can also build up hairy declarations from the outside in, using a substitution method. So,
int x(); -- x is a function returning int
int (*p)(); -- replace x with (*p) to get a pointer to a function
returning int
int (*a[2])(); -- replace p with a[2] to get an array of pointers
to functions returning int
int (*(*q)[2])(); -- replace a with (*q) to get a pointer to an array
of pointers to functions returning int
int (*(*g())[2])(); -- replace q with g() to get a function returning
a pointer to an array of pointers to functions
returning int.
Same result, different path. I prefer the first method, but either one should work.
Many people recommend using typedef to make things easier to read:
typedef int ifunc(); // ifunc is a synonym for "function returning int"
typedef ifunc *pifunc; // pifunc is a synonym for "pointer to function
// returning int
typedef pifunc farr[2]; // farr is a synonym for "2-element array of
// pointer to function returning int
typedef farr *pfarr; // pfarr is a synonym for "pointer to 2-element
// array of pointer to function returning int
pfarr g()
{
pfarr f = malloc(sizeof *f);
(*f)[0] = foo;
(*f)[1] = bar;
return f;
}
int main(void)
{
pfarr p = g();
int x, y;
x = (*(*p)[0])();
y = (*(*p)[1])();
...
}
Yes, the declarations are easier to read, but there's no connection between the declaration of pand the expression (*(*p)[1])(). You'd have to grovel back through all the typedefs to understand why that expression is written the way it is, building up a mental map for each typedef.
Yes, declarations like int (*(*g())[2])() are designed to make your eyes glaze over, hiding all that behind a typedef makes the situation worse IMO.
int **arr = x();?