Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

int (*call_vec[])(void) ?

58 views
Skip to first unread message

G G

unread,
Jun 20, 2019, 12:51:16 AM6/20/19
to
i saw this on the internet
could you please explain?

int anArray[] = { 6, 7, 8, 9 } --- array initialized
such that: anArray[0] = 6
anArray[1] = 7
anArray[2] = 8
anArray[3] = 9

int *ptr --- is a pointer to int

int *(ptr[4]) ---- is an array of pointers to int ?

int *ptr[4] ---- ? (same as above ?)

int ( *ptr[]) (void) --- ouch?

thanks.

G G

unread,
Jun 20, 2019, 1:32:11 AM6/20/19
to


> int ( *ptr[]) (void) --- ouch?
>
> thanks.

i found the answer i do believe :

from: https://stackoverflow.com/questions/252748/how-can-i-use-an-array-of-function-pointers



int sum(int a, int b);
int subtract(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int (*p[4]) (int x, int y);

int main(void)
{
int result;
int i, j, op;

p[0] = sum; /* address of sum() */
p[1] = subtract; /* address of subtract() */
p[2] = mul; /* address of mul() */
p[3] = div; /* address of div() */
[...]

To call one of those function pointers:

result = (*p[op]) (i, j); // op being the index of one of the four functions

new question : is there a better way to do this using objects?

Paavo Helde

unread,
Jun 20, 2019, 2:43:24 AM6/20/19
to
In C++ the above can be written e.g. as:

#include <vector>
#include <functional>

using func_t = std::function<int(int, int)>;

std::vector<func_t> p = {
[](int x, int y) {return x + y; },
[](int x, int y) {return x - y; },
[](int x, int y) {return x * y; },
[](int x, int y) {return x / y; },
};

int main() {
// ...
}




Bart

unread,
Jun 20, 2019, 6:22:12 AM6/20/19
to
'Ouch' as in 'what the hell does this mean', or 'what do you use it for'?

If the former, then you might try: https://cdecl.org, which turns such
declarations into English, or vice versa.

However - 'ptr' appears to mean something special there, and generates a
syntax error. So try a different name, like 'p'.

David Brown

unread,
Jun 20, 2019, 8:16:25 AM6/20/19
to
On 20/06/2019 12:22, Bart wrote:
> On 20/06/2019 05:51, G G wrote:
>> i saw this on the internet
>> could you please explain?
>>
>> int anArray[] = { 6, 7, 8, 9 }  --- array initialized
>>   such that: anArray[0] = 6
>>                     anArray[1] = 7
>>                     anArray[2] = 8
>>                     anArray[3] = 9
>>
>> int *ptr  --- is a pointer to int

It is common in C++, but by no means universal, to write this as

int* ptr;

This reads as "ptr is a pointer-to-int".

In C, it is common but far from universal to write:

int *ptr;

Reading as "*ptr is an int".

C++ emphasises the type, C emphasises the use of the identifier.

>>
>> int *(ptr[4])  ---- is an array of pointers to int ?
>>
>> int *ptr[4] ---- ? (same as above ?)

If you write this as:

int* ptr[4];

it becomes clearer.

>>
>> int ( *ptr[]) (void) --- ouch?
>>
>

C declarations are based on their usage. So this means that "ptr[100]"
would be a pointer to a function that takes no parameters (void), and
returns int. So "ptr" is an array of such pointer functions.

You can't have "int ( *ptr[]) (void);" on its own, just as you can't
define "int x[];" on its own, as the compiler doesn't know the number of
elements. You have to have a size for the array, or an "extern".


> 'Ouch' as in 'what the hell does this mean', or 'what do you use it for'?
>
> If the former, then you might try: https://cdecl.org, which turns such
> declarations into English, or vice versa.
>
> However - 'ptr' appears to mean something special there, and generates a
> syntax error. So try a different name, like 'p'.

Just to be clear - this is an artefact of the cdecl.org website. "ptr"
has no special meaning in C or C++.

If you find cdecl.org a useful tool, great. Personally, I much prefer
to use typedefs to make complex types clearer. Obviously you can only
do that when you write code - when reading other people's code, you have
to understand what /they/ write.

So if this array was for a collection of prime number generator
functions, I'd use:

typedef int (*FPrimeGenerator)(void);

extern FPrimeGenerator generatorFunctions[];


James Kuyper

unread,
Jun 20, 2019, 8:33:18 AM6/20/19
to
On 6/20/19 12:51 AM, G G wrote:
> i saw this on the internet
> could you please explain?
>
> int anArray[] = { 6, 7, 8, 9 } --- array initialized
> such that: anArray[0] = 6
> anArray[1] = 7
> anArray[2] = 8
> anArray[3] = 9
>
> int *ptr --- is a pointer to int
>
> int *(ptr[4]) ---- is an array of pointers to int ?

Keep in mind the basic principle of C declaration: declaration syntax
mirrors the corresponding expression syntax. That declaration says that
*(ptr[i]) is a valid expression for any value of i greater than 0 and
less than 4, and that the type of that expression is "int". In the
expression *(ptr[i]), the parentheses are unnecessary - it has exactly
the same meaning as *ptr[i]. The same is true of the corresponding
declaration. Such unnecessary parentheses are permitted in declarations,
but should be avoided, because they can be confusing, as you have seen.

> int *ptr[4] ---- ? (same as above ?)

>
> int ( *ptr[]) (void) --- ouch?

This is one of ways that the basic principle breaks down. (void) is a
parenthesized argument list for a function, with "void" indicating that
the function takes no arguments.

The empty square brackets indicate that an array is being declared, with
the length of the array being determined by the number of initializers
provided for that array. You don't provide the entire declaration, but
for the sake of argument let's pretend that four initializers are
provided. Then this declaration says that the expression (*ptr[i])() is
a valid expression for 0<=i && i<4, and that the type of that expression
is "int". Therefore, ptr is an array, ptr[i] is an element of that
array, *ptr[i] is a function, *ptr[i]() calls that function, and has the
type int. Therefore, ptr is an array of pointers to functions that take
no argument and return an int.

G G

unread,
Jun 20, 2019, 9:35:40 AM6/20/19
to

G G

unread,
Jun 20, 2019, 9:42:23 AM6/20/19
to

> >
> > >
> > > int ( *ptr[]) (void) --- ouch?
> >
> > This is one of ways that the basic principle breaks down. (void) is a
> > parenthesized argument list for a function, with "void" indicating that
> > the function takes no arguments.
> >
> > The empty square brackets indicate that an array is being declared, with
> > the length of the array being determined by the number of initializers
> > provided for that array. You don't provide the entire declaration, but
> > for the sake of argument let's pretend that four initializers are
> > provided. Then this declaration says that the expression (*ptr[i])() is
> > a valid expression for 0<=i && i<4, and that the type of that expression
> > is "int". Therefore, ptr is an array, ptr[i] is an element of that
> > array, *ptr[i] is a function, *ptr[i]() calls that function, and has the
> > type int. Therefore, ptr is an array of pointers to functions that take
> > no argument and return an int.

thanks
i don't think i'm asking this right but, here we go
in OOP, is this still best, or oop way of handling task needing to be done
based on a value. i know, i'm sorry, i don't think i know enough yet
to ask the question intelligently.

anyway thanks again.

James Kuyper

unread,
Jun 20, 2019, 9:51:34 AM6/20/19
to
Yes, you do need to learn how to ask the question better. It depends
entirely upon the task that needs to be done, which you haven't
specified. There are certainly tasks for which an array of function
pointers is the best approach - but I have no idea whether the task you
want to perform is one of them. In C++, an array of pointers to function
objects might be a better approach; or maybe not, depending upon the
task to be done.

Bart

unread,
Jun 20, 2019, 10:02:40 AM6/20/19
to
What's the difference between an array of function pointers, and an
array of pointers to function objects?

Ben Bacarisse

unread,
Jun 20, 2019, 10:55:27 AM6/20/19
to
David Brown <david...@hesbynett.no> writes:
<cut>
>> On 20/06/2019 05:51, G G wrote:
>>> int ( *ptr[]) (void) --- ouch?
>
> C declarations are based on their usage. So this means that "ptr[100]"
> would be a pointer to a function that takes no parameters (void), and
> returns int. So "ptr" is an array of such pointer functions.
>
> You can't have "int ( *ptr[]) (void);" on its own, just as you can't
> define "int x[];" on its own, as the compiler doesn't know the number of
> elements. You have to have a size for the array, or an "extern".

You are making a C and C++ mixed reply so it's worth pointing out that
both

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

are OK in C. Unless there is a further definition with a size, both
will be assumed to be 1-element arrays.

--
Ben.

David Brown

unread,
Jun 20, 2019, 11:37:44 AM6/20/19
to
Really? I had assumed it was a gcc extension, and didn't check for
details in the standard. It is unlikely to be good style, even if it is
allowed.

Ben Bacarisse

unread,
Jun 20, 2019, 1:29:11 PM6/20/19
to
No, it's standard C.

> It is unlikely to be good style, even if it is
> allowed.

Indeed. In fact I can't think of any purpose other than to allow old
code to pass. It's just a hang-over.

--
Ben.

Chris Vine

unread,
Jun 20, 2019, 5:02:14 PM6/20/19
to
You would not normally keep an array of pointers to std::function
objects: you would keep an array of std::function objects.
std::function objects are class templates with a call operator which
hand off to a virtual function, whose "innards" are allocated on free
store, and they can take anything which is callable (they perform type
erasure). In particular they can take a closure - either a lambda
expression with captured variable(s) or the return value of std::bind.

lambda expressions which are not closures are implicitly convertible to
function pointers. I would use an array of function pointers where
there will be no closures and an array of std::function objects
otherwise, on the grounds of efficiency.

James Kuyper

unread,
Jun 20, 2019, 5:34:17 PM6/20/19
to
> array of pointers to function objects.

A function object is an object that has an overloaded operator():

int function(int a, int b) { return 5*a+b;}

class function_object{
const int multiplier;
public:
function_object(int mult) : multiplier(mult) {};
operator()(int a, int b) const { return multiplier*a + b; }
} five(5);

Note: this is untested code; I don't currently have access to a compiler
that I can used to check it, so it may contain some trivial errors.
Sorry.

function(3,4) and five(3,4) perform exactly the same calculation.

James Kuyper

unread,
Jun 20, 2019, 5:35:46 PM6/20/19
to
On Thursday, June 20, 2019 at 10:55:27 AM UTC-4, Ben Bacarisse wrote:
...
> You are making a C and C++ mixed reply so it's worth pointing out that
> both
>
> int x[];
> int (*ptr[])(void);
>
> are OK in C. Unless there is a further definition with a size, both
> will be assumed to be 1-element arrays.

And they will be zero-initialized, which in the case of the function pointer, means it will be a null pointer.

James Kuyper

unread,
Jun 20, 2019, 5:40:34 PM6/20/19
to
One way it's used is to declare an array with an unspecified size and
external linkage, which can be useful if users don't need to know the
size, and it might change. Only in the module where that array is
actually defined does it have a known size.

Chris Vine

unread,
Jun 20, 2019, 6:06:04 PM6/20/19
to
A function object does not have to have an overloaded call operator. It
just has to have a call operator.

But why on earth would you keep an array of pointers to such things?
You would either keep an array of 'function_objects' since they only
have an int member or (if you were to allocate them on free store)
an array of std::unique_ptr<function_object>.

In practice you wouldn't do either of those things: if you had the
multiplier as a closure as above you would probably use an array of
std::function objects wrapping lambda expressions.

Ben Bacarisse

unread,
Jun 20, 2019, 6:07:48 PM6/20/19
to
James Kuyper <james...@alumni.caltech.edu> writes:

> On Thursday, June 20, 2019 at 1:29:11 PM UTC-4, Ben Bacarisse wrote:
>> David Brown <david...@hesbynett.no> writes:
>>
>> > On 20/06/2019 16:55, Ben Bacarisse wrote:
>> >> David Brown <david...@hesbynett.no> writes:
>> >> <cut>
>> >>>> On 20/06/2019 05:51, G G wrote:
>> >>>>> int ( *ptr[]) (void) --- ouch?
>> >>>
>> >>> C declarations are based on their usage. So this means that "ptr[100]"
>> >>> would be a pointer to a function that takes no parameters (void), and
>> >>> returns int. So "ptr" is an array of such pointer functions.
>> >>>
>> >>> You can't have "int ( *ptr[]) (void);" on its own, just as you can't
>> >>> define "int x[];" on its own, as the compiler doesn't know the number of
>> >>> elements. You have to have a size for the array, or an "extern".

This:-----------------------------------------------------------^

>> >> You are making a C and C++ mixed reply so it's worth pointing out that
>> >> both
>> >>
>> >> int x[];
>> >> int (*ptr[])(void);
>> >>
>> >> are OK in C. Unless there is a further definition with a size, both
>> >> will be assumed to be 1-element arrays.
>> >
>> > Really? I had assumed it was a gcc extension, and didn't check for
>> > details in the standard.
>>
>> No, it's standard C.
>>
>> > It is unlikely to be good style, even if it is
>> > allowed.
>>
>> Indeed. In fact I can't think of any purpose other than to allow old
>> code to pass. It's just a hang-over.
>
> One way it's used is to declare an array with an unspecified size and
> external linkage, which can be useful if users don't need to know the
> size, and it might change. Only in the module where that array is
> actually defined does it have a known size.

The "it" I was referring to was the original it -- that form without a
size or extern. With a size in one translation unit and an extern in
another, it's not an uncommon C usage.

--
Ben.

Keith Thompson

unread,
Jun 20, 2019, 6:18:16 PM6/20/19
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
[...]
> You are making a C and C++ mixed reply so it's worth pointing out that
> both
>
> int x[];
> int (*ptr[])(void);
>
> are OK in C. Unless there is a further definition with a size, both
> will be assumed to be 1-element arrays.

That seems to be the intent for C, but the wording in the C standard is
flawed, though the intent is stated explicitly in a non-normative
example. (We discussed this in comp.lang.c and comp.std.c in 2012.)

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

James Kuyper

unread,
Jun 20, 2019, 9:14:03 PM6/20/19
to
On 6/20/19 6:05 PM, Chris Vine wrote:
> On Thu, 20 Jun 2019 14:34:06 -0700 (PDT)
> James Kuyper <james...@alumni.caltech.edu> wrote:
>> On Thursday, June 20, 2019 at 10:02:40 AM UTC-4, Bart wrote:
>>> On 20/06/2019 14:51, James Kuyper wrote:
...
>>>> specified. There are certainly tasks for which an array of function
>>>> pointers is the best approach - but I have no idea whether the task you
>>>> want to perform is one of them. In C++, an array of pointers to function
>>>> objects might be a better approach; or maybe not, depending upon the
>>>> task to be done.
>>>>
>>>
>>> What's the difference between an array of function pointers, and an
>>> array of pointers to function objects.
>>
>> A function object is an object that has an overloaded operator():
>>
>> int function(int a, int b) { return 5*a+b;}
>>
>> class function_object{
>> const int multiplier;
>> public:
>> function_object(int mult) : multiplier(mult) {};
>> operator()(int a, int b) const { return multiplier*a + b; }
>> } five(5);
>>
>> Note: this is untested code; I don't currently have access to a compiler
>> that I can used to check it, so it may contain some trivial errors.
>> Sorry.
>>
>> function(3,4) and five(3,4) perform exactly the same calculation.
>
> A function object does not have to have an overloaded call operator. It
> just has to have a call operator.

Any declaration of an operator() function is an operator overload.

> But why on earth would you keep an array of pointers to such things?

In any context in which an array of function pointers might be useful,
and array of pointers to function objects might be viable alternative.
Or it might not be. If it is viable alternative, it might be a superior
one. It depends very much on the task to be performed.

> You would either keep an array of 'function_objects' since they only
> have an int member or (if you were to allocate them on free store)
> an array of std::unique_ptr<function_object>.

std::unique_ptr<> is included in what I meant by the term "pointer" in
this context.

> In practice you wouldn't do either of those things: if you had the
> multiplier as a closure as above you would probably use an array of

Don't take the details of my example too literally. I was merely
providing the simplest non-trivial example I could think of to show Bart
what a function object is. Any real world example could easily be a lot
more complicated and a lot more heterogenous - for example, the pointers
could be to a base class, with the actual function objects they point at
being of derived classes - which is a good reason for using an array of
pointers to function objects, rather than an array of function objects.

> std::function objects wrapping lambda expressions.

That also is included in what I meant.

Chris Vine

unread,
Jun 21, 2019, 6:58:34 AM6/21/19
to
On Thu, 20 Jun 2019 21:13:51 -0400
Really?

Anyway, it seems odd to give an array of pointers to function objects
to a beginner as an example of an alternative to an array of function
pointers. (A function pointer is a callable object, as is a function
object, but a pointer to a function object is not.)

> > In practice you wouldn't do either of those things: if you had the
> > multiplier as a closure as above you would probably use an array of
>
> Don't take the details of my example too literally. I was merely
> providing the simplest non-trivial example I could think of to show Bart
> what a function object is. Any real world example could easily be a lot
> more complicated and a lot more heterogenous - for example, the pointers
> could be to a base class, with the actual function objects they point at
> being of derived classes - which is a good reason for using an array of
> pointers to function objects, rather than an array of function objects.

Types with virtual overridden call operators, held by unique_ptr? Use
std::function.

> > std::function objects wrapping lambda expressions.
>
> That also is included in what I meant.

An array of std::function objects, which is a perfectly reasonable
alternative to an array of function pointers, is an array of function
objects, not an array of pointers to function objects.

Tim Rentsch

unread,
Jun 22, 2019, 7:31:01 AM6/22/19
to
Paavo Helde <myfir...@osa.pri.ee> writes:

> On 20.06.2019 8:32, G G wrote:
>>
>>
>> int sum(int a, int b);
>> int subtract(int a, int b);
>> int mul(int a, int b);
>> int div(int a, int b);
>>
>> int (*p[4]) (int x, int y);
>>
>> int main(void)
>> {
>> int result;
>> int i, j, op;
>>
>> p[0] = sum; /* address of sum() */
>> p[1] = subtract; /* address of subtract() */
>> p[2] = mul; /* address of mul() */
>> p[3] = div; /* address of div() */
>> [...]

Normally these initializations would be done as part of the
declaration:

int (*p[4])( int x, int y ) = { sum, subtract, mul, div };

>> To call one of those function pointers:
>>
>> result = (*p[op]) (i, j); // op being the index of one of the four functions

Or just

result = p[op]( i, j );

>> new question : is there a better way to do this using objects?
>
> In C++ the above can be written e.g. as:
>
> #include <vector>
> #include <functional>
>
> using func_t = std::function<int(int, int)>;
>
> std::vector<func_t> p = {
> [](int x, int y) {return x + y; },
> [](int x, int y) {return x - y; },
> [](int x, int y) {return x * y; },
> [](int x, int y) {return x / y; },
> };
>
> int main() {
> // ...
> }

Since none of the lambdas capture any environment, this can be
shortened to:

int (*p[])( int, int ) = {
0 new messages