How (*ptr_fun1)(10) and ptr_fun1(10) are same in the below code
Code:
#include<stdio.h>
void fun1(int a)
{
printf("It is %d\n",a);
}
int main()
{
void (*ptr_fun1)(int);
ptr_fun1 = fun1;
/*
ex-
ptr_fun1 fun1
+----+ +-----+
+1000+ +code +
+----+ +-----+
1234 1000
fun1(10); <=> ptr_fun1(10); //how
*/
printf("%d\n%d",ptr_fun1(10),(*ptr_fun1)(20));
return 0;
}
output
10
20
Can some one please explain how it works.
The syntax for declaring (and using) function pointers in C (and C++) is one of the most puzzling aspects of the language for beginners. I shall try to explain a little, here.
First, let's consider pointers to 'simple' types (we'll take the 'int' type as an example). In this case, declaring a variable of the type is trivial: int N; Also, declaring a pointer to an int is also trivial: int *pN;We can interpret this second declaration in terms of 'evaluating' the '*' operator, which means "get the object that resides at the given address." So, in int *pN we are declaring that "the object that lies at the address "pN" is an int.
For functions, this is not so simple! Take a case of a function that takes an int as its (only) argument and returns an int value: int IFunc(int arg);. This is also very straightforward.
But how could we declare a pointer to such a function? We cannot simply apply the same logic as for the 'simple' types (by preceding with a * operator), like this:
int *pIFunc(int arg);
Because this would declare a function that takes an int arg and returns a pointer to an int.
So, the early implementors of the C language had to come up with something better - and completely unambiguous. So they decided to use the syntax of putting the "*NAME" section in parentheses, to isolate that 'dereference' operation from the function's definition:
int (*pIFunc)(int arg);
So, when faced with anything that looks remotely like this: < typename > (*Name1)(...); (where < typename > is any allowable C-type, like int, void, double, or even 'compound' types such as int*, and the "..." inside the second set of brackets can be either empty or a list of other 'types'), recognize it as a declaration of a function pointer (or as dereferencing a function pointer). To get the underlying function 'signature' (or invocation), just remove the first set of brackets and the contained *. So, for:
(*ptr_fun1)(20)
you can read:
ptr_fun1(20)
And, for:
void (*ptr_fun1)(int);
you can see that ptr_fun has the following signature:
void ptr_fun1(int);
I hope this makes things a bit clearer. Feel free to ask for further clarification and/or explanations.
I'm thinking about the difference between:
void *signal(int, void (*)(int))(int)
and
void (*signal(int, void (*)(int)))(int)
I know the latter is from here - Example #3: The ``Ultimate'' (it's a hilarious learning experience when I was trying speak out loud to understand it):
signal is a function takes (int, void (*)(int)) as input and returns a pointer to another function that takes (int) and returns void.
For the former I'm thinking that since the last (int) will have higher precedence than * so it should be a syntax error, but from cdecl.org the result is:
["] declare signal as function (int, pointer to function (int) returning void) returning function (int) returning pointer to void [."]
So I need a check.
One has to differentiate between grammar and semantics. cdecl.org only gives you the grammatical meaning of whatever declarator you type into it. In your first example, you have indeed a grammatically correct declaration of signal as a function returning a function. However, C does not allow functions to return other functions:
N1570 6.7.6.3 §1:
A function declarator shall not specify a return type that is a function type or an array type.
So while this declaration is grammatically correct, it is semantically invalid. In other words: While the C syntax makes it possible to write "function returning a function", you're not allowed to actually have a function that returns a function in a program. Just like the English language (or any language for that matter) also allows you to express all sorts of thoughts that would physically be impossible to carry out…
The most important part here is... you don't need to learn this, it is a very poorly designed part of the language. You can scroll down to the bottom of the answer to find the sane, professional solution.
Otherwise, if you insist, it goes like this...
When trying to return a function pointer from a function, the type of the function pointer gets split up. If you want to return a function pointer void(*)(void), then this poor function pointer gets split up in 3 parts. Lets call them like this:
void is A, the return type of the pointed-at function.
(*) is B, marking this a pointer to function, rather than a function.
(void) is C, the parameters of the pointed-at function.
Then if we want to stick this as a return type into some other icky function declaration, they end up like this:
#define A void
#define B *
#define C (void)
// A (B) C equals void(*)(void)
A (B madness(int, void (*fp)(int))) C;
where A, B and C are the parts of our poor function pointer to be returned, madness is the name of the function, and the rest is some mess used as parameters by the function itself.
If we omit the B part, it will be interpreted like a function returning another function of type void f (void); which isn't valid. The syntax allows it but not the language specification.
Similarly, int foo (void) [3]; - a function returning an array, is not allowed either.
Pondering these things is the road to madness and it makes the code unreadable. Professional programmers use typedef.
Given
void (*madness(int, void (*f)(int)))(int);
replace it with:
typedef void func_t (int);
func_t* sanity (int, func_t* f);
I just saw a picture today and think I'd appreciate explanations. So here is the picture:
Transcription: "C isn't that hard: void (*(*f[])())() defines f as an array of unspecified size, of pointers to functions that return pointers to functions that return void."
I found this confusing and wondered if such code is ever practical. I googled the picture and found another picture in this reddit entry, and here is that picture:
Transcription: "So the symbols can be read: f [] * () * () void. f is an array of pointers that take no argument and return a pointer that takes no argument and returns void".
So this "reading spirally" is something valid? Is this how C compilers parse?
It'd be great if there are simpler explanations for this weird code.
Apart from all, can this kind of code be useful? If so, where and when?
There is a question about "spiral rule", but I'm not just asking about how it's applied or how expressions are read with that rule. I'm questioning usage of such expressions and spiral rule's validity as well. Regarding these, some nice answers are already posted.
There is a rule called the "Clockwise/Spiral Rule" to help find the meaning of a complex declaration.
From c-faq:
There are three simple steps to follow:
Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements:
[X] or []
=> Array X size of... or Array undefined size of...
(type1, type2)
=> function passing type1 and type2 returning...
*
=> pointer(s) to...
Keep doing this in a spiral/clockwise direction until all tokens have been covered.
Always resolve anything in parenthesis first!
You can check the link above for examples.
Also note that to help you there is also a website called:
http://www.cdecl.org
You can enter a C declaration and it will give its english meaning. For
void (*(*f[])())()
it outputs:
declare f as array of pointer to function returning pointer to function returning void
EDIT:
As pointed out in the comments by Random832, the spiral rule does not address array of arrays and will lead to a wrong result in (most of) those declarations. For example for int **x[1][2]; the spiral rule ignores the fact that [] has higher precedence over *.
When in front of array of arrays, one can first add explicit parentheses before applying the spiral rule. For example: int **x[1][2]; is the same as int **(x[1][2]); (also valid C) due to precedence and the spiral rule then correctly reads it as "x is an array 1 of array 2 of pointer to pointer to int" which is the correct english declaration.
Note that this issue has also been covered in this answer by James Kanze (pointed out by haccks in the comments).
The "spiral" rule kind of falls out of the following precedence rules:
T *a[] -- a is an array of pointer to T
T (*a)[] -- a is a pointer to an array of T
T *f() -- f is a function returning a pointer to T
T (*f)() -- f is a pointer to a function returning T
The subscript [] and function call () operators have higher precedence than unary *, so *f() is parsed as *(f()) and *a[] is parsed as *(a[]).
So if you want a pointer to an array or a pointer to a function, then you need to explicitly group the * with the identifier, as in (*a)[] or (*f)().
Then you realize that a and f can be more complicated expressions than just identifiers; in T (*a)[N], a could be a simple identifier, or it could be a function call like (*f())[N] (a -> f()), or it could be an array like (*p[M])[N], (a -> p[M]), or it could be an array of pointers to functions like (*(*p[M])())[N] (a -> (*p[M])()), etc.
It would be nice if the indirection operator * was postfix instead of unary, which would make declarations somewhat easier to read from left to right (void f[]*()*(); definitely flows better than void (*(*f[])())()), but it's not.
When you come across a hairy declaration like that, start by finding the leftmost identifier and apply the precedence rules above, recursively applying them to any function parameters:
f -- f
f[] -- is an array
*f[] -- of pointers ([] has higher precedence than *)
(*f[])() -- to functions
*(*f[])() -- returning pointers
(*(*f[])())() -- to functions
void (*(*f[])())(); -- returning void
The signal function in the standard library is probably the type specimen for this kind of insanity:
signal -- signal
signal( ) -- is a function with parameters
signal( sig, ) -- sig
signal(int sig, ) -- which is an int and
signal(int sig, func ) -- func
signal(int sig, *func ) -- which is a pointer
signal(int sig, (*func)(int)) -- to a function taking an int
signal(int sig, void (*func)(int)) -- returning void
*signal(int sig, void (*func)(int)) -- returning a pointer
(*signal(int sig, void (*func)(int)))(int) -- to a function taking an int
void (*signal(int sig, void (*func)(int)))(int); -- and returning void
At this point most people say "use typedefs", which is certainly an option:
typedef void outerfunc(void);
typedef outerfunc *innerfunc(void);
innerfunc *f[N];
But...
How would you use f in an expression? You know it's an array of pointers, but how do you use it to execute the correct function? You have to go over the typedefs and puzzle out the correct syntax. By contrast, the "naked" version is pretty eyestabby, but it tells you exactly how to use f in an expression (namely, (*(*f[i])())();, assuming neither function takes arguments).
In C, declaration mirrors usage—that’s how it’s defined in the standard. The declaration:
void (*(*f[])())()
Is an assertion that the expression (*(*f[i])())() produces a result of type void. Which means:
f must be an array, since you can index it:
f[i]
The elements of f must be pointers, since you can dereference them:
*f[i]
Those pointers must be pointers to functions taking no arguments, since you can call them:
(*f[i])()
The results of those functions must also be pointers, since you can dereference them:
*(*f[i])()
Those pointers must also be pointers to functions taking no arguments, since you can call them:
(*(*f[i])())()
Those function pointers must return void
The “spiral rule” is just a mnemonic that provides a different way of understanding the same thing.
So this "reading spirally" is something valid?
Applying spiral rule or using cdecl are not valid always. Both fails in some cases. Spiral rule works for many cases, but it is not universal.
To decipher complex declarations remember these two simple rules:
Always read declarations from inside out: Start from innermost, if any, parenthesis. Locate the identifier that's being declared, and start deciphering the declaration from there.
When there is a choice, always favour [] and () over *: If * precedes the identifier and [] follows it, the identifier represents an array, not a pointer. Likewise, if * precedes the identifier and () follows it, the identifier represents a function, not a pointer. (Parentheses can always be used to override the normal priority of [] and () over *.)
This rule actually involves zigzagging from one side of the identifier to the other.
Now deciphering a simple declaration
int *a[10];
Applying rule:
int *a[10]; "a is"
^
int *a[10]; "a is an array"
^^^^
int *a[10]; "a is an array of pointers"
^
int *a[10]; "a is an array of pointers to `int`".
^^^
Let's decipher the complex declaration like
void ( *(*f[]) () ) ();
by applying the above rules:
void ( *(*f[]) () ) (); "f is"
^
void ( *(*f[]) () ) (); "f is an array"
^^
void ( *(*f[]) () ) (); "f is an array of pointers"
^
void ( *(*f[]) () ) (); "f is an array of pointers to function"
^^
void ( *(*f[]) () ) (); "f is an array of pointers to function returning pointer"
^
void ( *(*f[]) () ) (); "f is an array of pointers to function returning pointer to function"
^^
void ( *(*f[]) () ) (); "f is an array of pointers to function returning pointer to function returning `void`"
^^^^
Here is a GIF demonstrating how you go (click on image for larger view):
The rules mentioned here is taken from the book C Programming A Modern Approach by K.N KING.
It's only a "spiral" because there happens to be, in this declaration, only one operator on each side within each level of parentheses. Claiming that you proceed "in a spiral" generally would suggest you alternate between arrays and pointers in the declaration int ***foo[][][] when in reality all of the array levels come before any of the pointer levels.
I doubt constructions like this can have any use in real life. I even detest them as interview questions for the regular developers (likely OK for compiler writers). typedefs should be used instead.
As a random trivia factoid, you might find it amusing to know that there's an actual word in English to describe how C declarations are read: Boustrophedonically, that is, alternating right-to-left with left-to-right.
Reference: Van der Linden, 1994 - Page 76
Regarding the usefulness of this, when working with shellcode you see this construct a lot:
int (*ret)() = (int(*)())code;
ret();
While not quite as syntactically complicated, this particular pattern comes up a lot.
More complete example in this SO question.
So while the usefulness to the extent in the original picture is questionable (I would suggest that any production code should be drastically simplified), there are some syntactical constructs that do come up quite a bit.
The declaration
void (*(*f[])())()
is just an obscure way of saying
Function f[]
with
typedef void (*ResultFunction)();
typedef ResultFunction (*Function)();
In practice, more descriptive names will be needed instead of ResultFunction and Function. If possible I would also specify the parameter lists as void.
I happen to be the original author of the spiral rule that I wrote oh so many years ago (when I had a lot of hair :) and was honored when it was added to the cfaq.
I wrote the spiral rule as a way to make it easier for my students and colleagues to read the C declarations "in their head"; i.e., without having to use software tools like cdecl.org, etc. It was never my intent to declare that the spiral rule be the canonical way to parse C expressions. I am though, delighted to see that the rule has helped literally thousands of C programming students and practitioners over the years!
For the record,
It has been "correctly" identified numerous times on many sites, including by Linus Torvalds (someone whom I respect immensely), that there are situations where my spiral rule "breaks down". The most common being:
char *ar[10][10];
As pointed out by others in this thread, the rule could be updated to say that when you encounter arrays, simply consume all the indexes as if written like:
char *(ar[10][10]);
Now, following the spiral rule, I would get:
"ar is a 10x10 two-dimensional array of pointers to char"
I hope the spiral rule carries on its usefulness in learning C!
P.S.:
I love the "C isn't hard" image :)
I found method described by Bruce Eckel to be helpful and easy to follow:
Defining a function pointer
To define a pointer to a function that has no arguments and no return
value, you say:
void (*funcPtr)();
When you are looking at a complex definition like
this, the best way to attack it is to start in the middle and work
your way out. “Starting in the middle” means starting at the variable
name, which is funcPtr. “Working your way out” means looking to the
right for the nearest item (nothing in this case; the right
parenthesis stops you short), then looking to the left (a pointer
denoted by the asterisk), then looking to the right (an empty argument
list indicating a function that takes no arguments), then looking to
the left (void, which indicates the function has no return value).
This right-left-right motion works with most declarations.
To review, “start in the middle” (“funcPtr is a ...”), go to the right
(nothing there – you're stopped by the right parenthesis), go to the
left and find the ‘*’ (“... pointer to a ...”), go to the right and
find the empty argument list (“... function that takes no arguments
... ”), go to the left and find the void (“funcPtr is a pointer to a
function that takes no arguments and returns void”).
You may wonder why *funcPtr requires parentheses. If you didn't use
them, the compiler would see:
void *funcPtr();
You would be declaring a function (that returns a
void*) rather than defining a variable. You can think of the compiler
as going through the same process you do when it figures out what a
declaration or definition is supposed to be. It needs those
parentheses to “bump up against” so it goes back to the left and finds
the ‘*’, instead of continuing to the right and finding the empty
argument list.
Complicated declarations & definitions
As an aside, once you figure out how the C and C++ declaration syntax
works you can create much more complicated items. For instance:
//: C03:ComplicatedDefinitions.cpp
/* 1. */ void * (*(*fp1)(int))[10];
/* 2. */ float (*(*fp2)(int,int,float))(int);
/* 3. */ typedef double (*(*(*fp3)())[10])();
fp3 a;
/* 4. */ int (*(*f4())[10])();
int main() {} ///:~
Walk through each one and use the right-left
guideline to figure it out. Number 1 says “fp1 is a pointer to a
function that takes an integer argument and returns a pointer to an
array of 10 void pointers.”
Number 2 says “fp2 is a pointer to a function that takes three
arguments (int, int, and float) and returns a pointer to a function
that takes an integer argument and returns a float.”
If you are creating a lot of complicated definitions, you might want
to use a typedef. Number 3 shows how a typedef saves typing the
complicated description every time. It says “An fp3 is a pointer to a
function that takes no arguments and returns a pointer to an array of
10 pointers to functions that take no arguments and return doubles.”
Then it says “a is one of these fp3 types.” typedef is generally
useful for building complicated descriptions from simple ones.
Number 4 is a function declaration instead of a variable definition.
It says “f4 is a function that returns a pointer to an array of 10
pointers to functions that return integers.”
You will rarely if ever need such complicated declarations and
definitions as these. However, if you go through the exercise of
figuring them out you will not even be mildly disturbed with the
slightly complicated ones you may encounter in real life.
Taken from: Thinking in C++ Volume 1, second edition, chapter 3, section "Function Addresses" by Bruce Eckel.
Remember these rules for C declares
And precedence never will be in doubt:
Start with the suffix, proceed with the prefix,
And read both sets from the inside, out.
-- me, mid-1980's
Except as modified by parentheses, of course. And note that the syntax for declaring these exactly mirrors the syntax for using that variable to get an instance of the base class.
Seriously, this isn't hard to learn to do at a glance; you just have to be willing to spend some time practising the skill. If you're going to maintain or adapt C code written by other people, it's definitely worth investing that time. It's also a fun party trick for freaking out other programmers who haven't learned it.
For your own code: as always, the fact that something can be written as a one-liner does't mean it should be, unless it is an extremely common pattern that has become a standard idiom (such as the string-copy loop). You, and those who follow you, will be much happier if you build complex types out of layered typedefs and step-by-step dereferences rather than relying on your ability to generate and parse these "at one swell foop." Performance will be just as good, and code readability and maintainability will be tremendously better.
It could be worse, you know. There was a legal PL/I statement that started with something like:
if if if = then then then = else else else = if then ...
void (*(*f[]) ()) ()
Resolving void >>
(*(*f[]) ()) () = void
Resoiving () >>
(*(*f[]) ()) = function returning (void)
Resolving * >>
(*f[]) () = pointer to (function returning (void) )
Resolving () >>
(*f[]) = function returning (pointer to (function returning (void) ))
Resolving * >>
f[] = pointer to (function returning (pointer to (function returning
(void) )))
Resolving [ ] >>
f = array of (pointer to (function returning (pointer to (function
returning (void) ))))
Can someone explain this line by line (character by character maybe, haha)?
typedef int (*funcptr)(); /* generic function pointer */
typedef funcptr (*ptrfuncptr)(); /* ptr to fcn returning g.f.p. */
funcptr start(), stop();
funcptr state1(), state2(), state3();
void statemachine()
{
ptrfuncptr state = start;
while(state != stop)
state = (ptrfuncptr)(*state)();
}
funcptr start()
{
return (funcptr)state1;
}
For example, I would like to know why there are () at the end of line 1. An answer like "that's just how you declare a pointer to a function" would be satisfying, but then when you declare a variable of that type, why only use "funcptr" without the ()?
Lines 4 and 5. Why do you have the () here? Those aren't functions, they're pointers to functions, right?
Line 9. Why doesn't "state" have ()? Still a pointer to a function as are the ones on lines 5 and 6.
Line 9. What is "start" without the ()?
Line 12. WHAT?! (I know what typecasting is. At least I think I do...)
Line 17. Why does "state1" require a typecast? It is of the type it's being cast as already. Or is it because it's missing the ()?
It would really help me to understand these concepts.
PS. This is for a microcontroller I'll use in an electronic Dummy Load I'm designing. Figured it's a good opportunity to learn more about C. The code is from http://c-faq.com/decl/recurfuncp.html
As noted in the question, this comes from the C FAQs web site. The question is:
Q: How can I declare a function that can return a pointer to a function of the same type? I'm building a state machine with one function for each state, each of which returns a pointer to the function for the next state. But I can't find a way to declare the functions—I seem to need a function returning a pointer to a function returning a pointer to a function returning a pointer to a function…, ad infinitum.
A: You can't quite do it directly. One way is to have the function return a generic function pointer (see question 4.13), with some judicious casts to adjust the types as the pointers are passed around:
And then there's a first example using the code shown in the SO question.
As the FAQ answer says, you can't create a function that returns a pointer to its own type of function, so you have to bludgeon the compiler into working.
Line 1: typedef int (*funcptr)();
This has the () at the end because without them, you'd have typedef int (*intptr); or typedef int *intptr; which is not what you want. The empty parentheses are an indeterminate — not empty — list of arguments. It is the way you declare a function pointer — before even trying to compile with my default compilation options, I modified the code to: typedef int (*funcptr)(void);.
A funcptr, therefore, is a pointer to a function that returns an int and (at least for the purposes of this discussion) takes no arguments.
Line 2: typedef funcptr (*ptrfuncptr)();
Don't try this without the intermediate type! This too is a pointer to a function, and the function returns a funcptr — and I used typedef funcptr (*ptrfuncptr)(void); to assert 'and takes no arguments'.
Line 4 & 5: funcptr start(), stop(); etc
These lines declare a set of 5 functions. Again, the argument lists are unspecified — so I'm going to treat them as having (void). These functions return a funcptr. However, their own type is not funcptr. This is the point made in the answer.
Indeed, treated as a name (without the parentheses), the type of start, stop, and state1 through state3 is ptrfuncptr — pointer to a function returning a funcptr.
Line 9: ptrfuncptr state = start;
The variable state is of type ptrfuncptr, and is initialized (without need for casting) to point at the function start. Note that this does not call the function; it merely initializes a variable, just as if you have int i = -37;, it initializes a variable i of type int to the value -37.
Line 12: state = (ptrfuncptr)(*state)();
Time to get the bludgeons out. This line contains a function call and a cast.
The original logic behind function pointers was the 'type mimics use' concept. For example, if you have:
int *p;
then in an expression, *p has the type int. With function pointers, you have:
int (*intfuncptr)();
and in an expression, (*intfuncptr)() represents an int; it is the result of invoking the function pointed at by intptrfunc. In pre-standard C, the (*pointer_to_function)() notation was the only way to use a pointer to function. Standard C allows you to omit the (* and ) around the pointer.
Thus, in modern notation, the line state = (ptrfuncptr)(*state)(); could also be written state = (ptrfuncptr)state();. When I learned C, this wasn't an option, so I still prefer the explicit 'this is invoking a function via a pointer to function' notation. The FAQ does mention this.
So, the line calls the function pointed to by state, and captures the return value in state. But the value returned by the function is a funcptr, not a ptrfuncptr, so we need to bludgeon the compiler into accepting that we know enough of what we're doing to remain silent. So, the (ptrfuncptr) cast does that.
Line 17: return (funcptr)state1;
Since start returns a funcptr, but state1 is a pointer to a function that returns a funcptr, the cast here is, once more, necessary to bludgeon the compiler into accepting the type mismatch. Without parentheses after it, state1 is just the name of the function, not an invocation of the function, and therefore has the type ptrfuncptr — pointer to a function returning a funcptr, not just funcptr which is what start is supposed to return. So, the cast is necessary.
For more mind-blowing function pointers, see:
Understanding typedefs for function pointer in C — examples, hint and tips, please
How typedef works for function pointers
Is it a good idea to typedefpointers? — general answer, no, but there's a strong exception for pointers to functions.
What are the various styles of defining a function returning a function pointer?
…and somewhere there's a question that discusses trivia like state = (ptrfuncptr)(******state)(); (using notation from this Q&A), and the mulitple stars work too…
I was grabbing information about pointers to functions when I found this declaration:
char (* ( *f())[])();
I tried to find out what is the meaning of it but I couldn't...
what does it refer to?
It breaks down as follows:
f -- f
f() -- is a function returning
*f() -- a pointer to
(*f())[] -- an array of
*(*f())[] -- pointer to
(*(*f())[])() -- function returning
char (*(*f())[])(); -- char
Postfix operators like [] and function call () bind before unary operators like *, so
*a[] -- is an array of pointer
(*a)[] -- is a pointer to an array
*f() -- is a function returning a pointer
(*f)() -- is a pointer to a function
Find the leftmost identifier and work your way out, applying those rules recursively for any function parameters.
Edit
In the comment to another answer, KerrekSB suggests using typedefs, which would certainly make the code scan more easily:
typedef char CharFunc();
typedef CharFunc *CharFuncPtr;
typedef CharFuncPtr CharFuncPtrArr[N];
typedef CharFuncPtrArr *CharFuncPtrArrPtr;
typedef CharFuncPtrArrPtr CharFuncPtrArrPtrFunc();
CharFuncPtrArrPtrFunc *f;
You could probably come up with a better naming convention. But even so,
CharFuncPtrArrPtrFunc *f;
sure looks nicer than
char (*(*f())[])();
But is it better?
In my experience, the answer is often "no", especially when pointer types are involved. What is the function that f points to supposed to look like? How do I call it? What parameters am I supposed to pass to it? What do I do with the value returned by the function f points to? How do I use it in an expression? I have to look up the definition of CharFuncPtrArrPtrFunc, which means I also have to look up the definition of CharFuncPtrArrPtr, and CharFuncPtrArr, etc., etc., etc., then I have to mentally puzzle out the resulting syntax for the call.
char (*(*f())[])(); borders on total unreadability, but it tells me at a glance how I should call the function f points to and how to use the return value.
declare f as function returning pointer to array of pointer to function returning char