First thing's first, the declaration you show is ill-formed. Not surprisingly, given how hard the declarator syntax in C can be. If you wanted an array of function pointers (something I strongly suspect), then the raw spelling is like this:
int *(*functions_array[4])();
Not much more readable, but at least syntactically correct. You can now index into it to obtain a function pointer for your use. E.g:
functions_array[0] = function;
functions_array[0](); // Call the function
But if you really wanted a pointer to an array (for reasons I can't fathom), the raw declarator is this:
int *(*(*functions_array_p)[4])();
With the now less appealing indexing to match:
(*functions_array_p)[0] = function;
(*functions_array_p)[0](); // Call the function
The parenthesis are required due to the regular precedence of * and [].
But the way to make working with it and defining it easier, is by introducing some type aliases. Primarily, for the function type:
typedef int* function_type();
Now the array declaration takes this far more readable form:
function_type* functions_array[4];
The asterisk in plain sight is inline with the generally good practice of not hiding away pointer semantics.
And for a pointer to an array:
function_type* (*functions_array)[4];
The declarator is still fairly regular looking.
1. As an aside, an empty parameter list in a C function declaration does not mean the function takes no arguments. It's an obsolescent feature providing a function with no prototype. The way forward is (void).
typedefs and combine them to what you need. That will help you and every other programmer read the code.&on the function name; the compiler provides it automatically.