views:

165

answers:

6

Is this correct?

int (*(*ptr)())[];

I know this is trivial, but I was looking at an old test about these kind of constructs, and this particular combination wasn't on the test and it's really driving me crazy; I just have to make sure. Is there a clear and solid understandable rule to these kind of declarations? (ie: pointer to... array of.. pointers to... functions that.... etc etc) Thanks!

R

+8  A: 

The right-left rule makes it easy.

int (*(*ptr)())[];can be interpreted as

Start from the variable name ------------------------------- ptr

Nothing to right but ) so go left to find * -------------- is a pointer

Jump out of parentheses and encounter () ----------- to a function that takes no arguments(in case of C unspecified number of arguments)

Go left, find * ------------------------------------------------ and returns a pointer

Jump put of parentheses, go right and hit [] ---------- to an array of

Go left again, find int ------------------------------------- ints.

Prasoon Saurav
There's nothing easy about this. I like to use typedefs to break it down a little.
Mark Ransom
Note though that the example isn't a valid declaration - to make it one, the array size needs to be specified.
caf
@caf: It makes the type an incomplete type but you can still use a pointer to an incomplete type in a declaration.
Charles Bailey
@Charles Bailey: So it does! I had no idea that a pointer to an incomplete array type was a useable type, but there you go. You surely *do* learn something new every day, as they say.
caf
A: 

Here's my solution...

int** (*func)();

Functor returning an array of int*'s. It isn't as complicated as your solution.

Clark Gaebel
+1  A: 

Using cdecl you get the following

cdecl> declare a as pointer to function returning pointer to  array of int;
Warning: Unsupported in C -- 'Pointer to array of unspecified dimension'
    (maybe you mean "pointer to object")
int (*(*a)())[]

This question from C-faq is similar but provides 3 approaches to solve the problem.

Praveen S
+4  A: 

In almost all situations where you want to return a pointer to an array the simplest thing to do is to return a pointer to the first element of the array. This pointer can be used in the same contexts as an array name an provides no more or less indirection than returning a pointer of type "pointer to array", indeed it will hold the same pointer value.

If you follow this you want a pointer to a function returning a pointer to an int. You can build this up (construction of declarations is easier than parsing).

Pointer to int:

int *A;

Function returning pointer to int:

int *fn();

pointer to function returning a pointer to int:

int *(*pfn)();

If you really want to return a pointer to a function returning a pointer to an array of int you can follow the same process.

Array of int:

int A[];

Pointer to array of int:

int (*p)[];

Function returning pointer ... :

int (*fn())[];

Pointer to fn ... :

int (*(*pfn)())[];

which is what you have.

Charles Bailey
A: 

If you feel like cheating:

typedef int(*PtrToArray)[5];
PtrToArray function();

int i = function;

Compiling that on gcc yields: invalid conversion from 'int (*(*)())[5]' to 'int'. The first bit is the type you're looking for.

Of course, once you have your PtrToArray typedef, the whole exercise becomes rather more trivial, but sometimes this comes in handy if you already have the function name and you just need to stick it somewhere. And, for whatever reason, you can't rely on template trickery to hide the gory details from you.

If your compiler supports it, you can also do this:

typedef int(*PtrToArray)[5];
PtrToArray function();

template<typename T> void print(T) {
    cout << __PRETTY_FUNCTION__ << endl;
}

print(function);

Which, on my computer box, produces void function(T) [with T = int (* (*)())[5]]

Being able to read the types is pretty useful, since understanding compiler errors is often dependent on your ability to figure out what all those parenthesis mean. But making them yourself is less useful, IMO.

Dennis Zickefoose
+1  A: 

You don't. Just split it up into two typedefs: one for pointer to int array, and one for pointer to functions. Something like:

typedef int (*IntArrayPtr_t)[];
typedef IntArrayPtr_t (*GetIntArrayFuncPtr_t)(void);

This is not only more readable, it also makes it easier to declare/define the functions that you are going to assign the variable:

IntArrayPtr_t GetColumnSums(void)
{ .... }

Of course this assumes this was a real-world situation, and not an interview question or homework. I would still argue this is a better solution for those cases, but that's only me. :)

Dysaster