nmuntz
nmuntz

Reputation: 1158

Mixed pointer, array and function type-declarations in C

A friend of mine was trying to test me on C (my strongest language is C++) and he asked me three questions which I could not answer:

Try to explain the following declarations:

1) int (*x)(int, char *, void *);
2) int (*x[10])(int, char *, void *);
3) int (**x[10])(int, char *, void *);

Can anyone explain these function declarations and explain what concepts are being used?

Upvotes: 8

Views: 2782

Answers (5)

hlovdal
hlovdal

Reputation: 28228

You need the cdecl program, which will give you a definite, correct answer to such questions. Learning to interpret such statements manually is doable and beneficial, but even so cdecl is extremely useful for checking if you have an correct answer.

prompt>cdecl
Type `help' or `?' for help
cdecl> explain int (*x)(int, char *, void *);
declare x as pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (*x[10])(int, char *, void *);
declare x as array 10 of pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (**x[10])(int, char *, void *);
declare x as array 10 of pointer to pointer to function (int, pointer to char, pointer to void) returning int
cdecl>

Upvotes: 32

Walt W
Walt W

Reputation: 3349

Well, the first one is a pointer to a function. In other words, it declares a variable "x" which points to a function of the following type:

int function(int, char*, void*);

And could be used as follows:

int myfunc(int a, char* b, void* c) {
    return a;
}

void acallingfunction() {
    int (*x)(int, char*, void*);
    x = myfunc;
    x(1, "hello", 0);
}

The second appears to be invalid syntax, but I may be wrong. If it had an asterisk before the x (such as int (*x[10])(int, char*, void*) ), it would be an array of function pointers, and would be used like a normal array:

x[3](1, "Hi there", 0);

The third is an array of pointers to function pointers, which doesn't seem practical, but is perfectly valid. An example usage might be:

void anothercaller() {
    int (*x)(int, char*, void*);
    int (**y)(int, char*, void*);
    x = myfunc;
    y = &x;
    (*y)(1, "hello", 0);
}

Note that of these, the first two are relatively common. Pointers to functions are used to accomplish callbacks and various Object-Oriented programming concepts in C. An array of pointers to functions might be used for an event table, to find the appropriate callback.

Note that all of those are, in fact, valid C++ as well. ;)

Edit: I committed the atrocities of void main() apparently.

Edit 2: As Chris Lutz points out below, they really should be wrapped in typedefs. Typedefs make code containing pointers to functions MUCH clearer.

Upvotes: 21

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507115

Since the syntax of C is like the one of C++ in this matter, geordi could be interesting to you. It is another good tool for teaching and learning those declarations (and other things related to C++ and sometimes, C too).

geordi: << ETYPE_DESC(x); int (*x)(int, char *, void *);
lvalue pointer to a function taking an integer, a pointer to a character, a pointer to anything, and returning an integer

geordi: << ETYPE_DESC(x); int (*x[10])(int, char *, void *);
lvalue array of 10 pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers

geordi: << ETYPE_DESC(x); int (**x[10])(int, char *, void *);
lvalue array of 10 pointers to pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers

As its page explains, it can do much more, including building a type for you

geordi: make type array of 10 pointers to functions taking an integer and returning void
void(*[10])(int)

If you know in principle how to declare things, but are unsure about just one thing, you may use parentheses:

geordi: make type ( void(int, bool) )*
void(*)(int, bool)

If you want to see how this looks like with an identifier in it, you may change the type of names, too

geordi: -c int x;
Success
geordi: make x a ( void(int, bool) )* and show
-c void (* x)(int, bool) ;

If you build up a declaration, but you are unsure about the precedence of the operators, then geordi's precedence functions can help you out

geordi: precedence *x(a, b)
*(x(a, b))

Upvotes: 3

Chris Lutz
Chris Lutz

Reputation: 75429

They are function pointers, as said above, but written rather obnoxiously (in my opinion). The way I would write them is:

typedef int (*funcptr)(int, char *, void *);

funcptr x;
funcptr x[10];
funcptr *x;

See Walt W's excellent answer for more about function pointers.

Upvotes: 6

tensaix2j
tensaix2j

Reputation: 462

  1. A function pointer
  2. An array of function pointers
  3. An array of pointers to function pointers

Upvotes: 7

Related Questions