Function Pointers

P

pete

"PAUSE" is not a portable system command.
In other words, it won't work on all systems.
The code you post here, should not be undefined.
Learnig how best to write portable or correct code,
is pretty much the whole point of reading this newgroup.

N869
3. Terms and definitions
3.18
[#1] undefined behavior
behavior, upon use of a nonportable or erroneous program
construct, of erroneous data, or of indeterminately valued
objects, for which this International Standard imposes no
requirements

4. Conformance
[#3] A program that is correct in all other aspects,
operating on correct data, containing unspecified behavior
shall be a correct program and act in accordance with
5.1.2.3.



Seriously, is it out of consideration for others,
and not because of a problem that you have?
I went onto my Windows box and ran a few programs.
None of them closed the
console when they were done.

It doesn't happen on my windows box
when I open a command prompt window either.
It happened when I ran a program directly from MSVC
by clicking on an icon that looks like a red exclamation mark,
but I don't do that anymore.

No. That's not the reason.
It doesn't make the code easier to compile.
 
K

Kenneth Brody

Frederick said:
Richard Heathfield posted:


Sorry, not sure what you mean.

He meant that your system() call caused the above error to appear on
his screen when he ran your program.
I tend to put:

system("PAUSE");

at the end of my code snippets because a lot of people use Windows;

Perhaps, but that's irrelevent in clc.
and on
Windows, a console windows disappears once the program has finished
execution.

Not for me, and I've been running Windows on some of my computers
since version 1.0 was in Alpha testing.

For example:

C:\temp>hello
Hello, world.

C:\temp>

Looks like my window is still there.

Even if running the program from within my IDE, I get a "press any
key to continue" prompt before the window closes.
It's just for convenience so that my snippets are easy to compile
straight-out-of-the-box.

I don't see how it helps to compile it. It may, on your system,
help you run it without the window disappearing. However, it only
hurts those not on Windows.

Why not simply add:

while ( getchar() != '\n' ) ;

Or:

printf("Press Enter to continue.\n");
fflush(stdout);
while ( getchar() != '\n' )
;

These will work on non-Windows platforms as well.

Of course, on most systems, the above code will simply annoy the user,
as they wonder "why do I need to press Enter to get this program to
exit?"

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
L

lovecreatesbeauty

What is the purpose of the function pointer? Why do you need a pointer
to a function.

A function pointer is used to pass a function without firing it. A
pointer provides an alternative way to access an object or a function.
I cannot really think of any application where this is
the only or even easiest solution to a problem.

A more complex example with function pointers is the function:

#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);

lovecreatesbeauty
 
B

Ben C

What is the purpose of the function pointer? Why do you need a pointer
to a function. I cannot really think of any application where this is
the only or even easiest solution to a problem. I'm sure there are
really good aplications for it I just cannot think of any, so if anyone
can tell me why a pointer to a function is nessisary and when it
can/should be used I would apreciate that. Thanks.

They're often useful when you have complicated data structures that you
want to iterate through. You write the function that finds its way
through the data structure once, and it calls a callback for each item
inside.

Something like this:

typedef int (*callback_t)(const struct record *record, void *handle);
extern int database_foreach(const struct database *db, callback_t cb);

Because database_foreach calls back whatever I pass in cb, I can use it
for all kinds of things without worrying how things are actually
arranged in the database and how to retrieve them. That code is written
once in database_foreach, and hidden away.

A common way to do this without callbacks, on the other hand, is
something like this:

extern db_iterator *database_start(const struct database *db);
extern const struct record *database_next(const struct database *db,
db_iterator *it);

Here the database code stores everything it needs to know about where it
got to and how to continue the iteration in *it, some kind of object it
creates specially to store this state in. In practice the contents of
*it will be the same sorts of things as are in the stack frame of
database_foreach.

On the other hand if you use database_foreach, the "handle" it calls
back the callback with will in many cases point to an object storing
state for whatever's going on "at the other end".

These are sometimes described as ways to "simulate coroutines in C". You
often find function pointers used in this kind of coroutine situation--
two or more operations which each need their own state and which work
together.
 
F

Frederick Gotham

lovecreatesbeauty posted:

A more complex example with function pointers is the function:

#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);


I like the hardcore method ; )



/* Hardcore method */

void (*signal_hardcore(int, void (*p)(int)))(int)
{
return p;
}


/* Dumbed-down method */

typedef void (*Ptr_FuncTakeIntReturnVoid)(int);

Ptr_FuncTakeIntReturnVoid signal_dumb( int, Ptr_FuncTakeIntReturnVoid p )
{
return p;
}


/* Both used the same way */

void Func(int) {}

int main(void)
{
signal_dumb( 0, Func );

signal_hardcore( 0, Func );
}
 
R

Richard Heathfield

Kenneth Brody said:

Of course, on most systems, the above code will simply annoy the user,
as they wonder "why do I need to press Enter to get this program to
exit?"

Ctrl-Alt-Del to begin, Start to finish, and now Enter to exit. Got to love
Windows.
 
C

Clever Monkey

What is the purpose of the function pointer? Why do you need a pointer
to a function. I cannot really think of any application where this is
the only or even easiest solution to a problem. I'm sure there are
really good aplications for it I just cannot think of any, so if anyone
can tell me why a pointer to a function is nessisary and when it
can/should be used I would apreciate that. Thanks.
Nori
[Disclaimer: I'm no wizard, but I have been handed a pile of decades-old
C code to maintain. I do what I can with what I have!]

We use function pointers in a few places to implement callbacks. This
allows a variety of calling contexts to run code that can "call back" to
that context to update the UI, get input, read properties &etc.

All without the called code having to know who is calling it.

In this specific case we have a sort of API call that can update the UI
to handle exceptional cases requiring interaction (e.g., "Are you sure
you want to destroy Orbital Death Lasers? (y/N)"), regardless of what
sort of UI that is. Add a UI/interface and all you have to do is change
the code you set the function pointer to -- you do not have to change
code that *other* UIs and interfaces may rely on.

Another use is when implementing a classic data structure like a map or
list. It is common enough for for the sort, search or compare functions
one needs for the data structure to be implemented as a pointer to a
function. This is a similar use to the standard qsort().
 
F

Frederick Gotham

Frederick Gotham posted:

I like the hardcore method ; )


Who's up for role play? I have an idea for a game!

You've to come up with as complicated a function signature as you can,
but... you also have to devise a story in order to justify its complexity.


OK I'm first!


How about some sort of "runtime-programmable calculator".

All of its operations can be performed using simple functions which all
have the same signature, e.g.:

int Add(int,int);
int Subtract(int,int);
int Divide(int,int);

The calculator must be supplied at runtime with 16 such functions.

The programmable calculator queries a database looking for these 16
operations, and receives a pointer to a 16-element-array of pointers to
functions. (It returns a pointer to an array of definite size rather than a
pointer to the first element of an arrary in order to emphasize that the
array's length must be 16.). Furthermore, in the same query, you must
supply the database with a callback function which it should invoke before
and after it goes checking the database, to indicate its current status.
The callback funtion should have the following signature:

void Indicate(int);


Okay here's what I've got:


/* Let's start off with an actual function */

#include <stdio.h>

int Addition(int const a, int const b)
{
int result = a + b;

printf( "The addition of %i and %i yields: %i\n", a, b, result );

return result;
}


/* Here's the callback function which gets invoked to
inform us of the database's current status. */

void Indicate(int) {}


/* Here's the function which accesses the database and retrieves
our mathematical operations as pointers to functions. */

int (*(*RetrieveOperations(void(*pCallback)(int)))[16])(int,int)
{
pCallback(0);

static int (*array[16])(int,int) =
{ Addition, Addition, Addition, Addition, Addition, Addition,
Addition, Addition, Addition, Addition, Addition, Addition,
Addition, Addition, Addition, Addition };

pCallback(1);

return &array;
}


int main(void)
{
int (*(*p_array)[16])(int,int) = RetrieveOperations(Indicate);


/* Now let's call a few functions */


(*p_array)[0](1,2);
(*p_array)[4](3,4);
(*p_array)[9](5,6);
(*p_array)[12](7,8);
}


Looking forward to reading others' contributions : )
 
K

Kenneth Brody

Frederick said:
Frederick Gotham posted:
I like the hardcore method ; )

Who's up for role play? I have an idea for a game!

You've to come up with as complicated a function signature as you can,
but... you also have to devise a story in order to justify its complexity.

OK I'm first!

How about some sort of "runtime-programmable calculator". [...]
int (*(*RetrieveOperations(void(*pCallback)(int)))[16])(int,int)
[...]

You forgot to mention that there are 4 modes of this calculator,
and therefore it needs to return an array of 4 pointers to these
16-element arrays.

Ready... Go!

Is it possible to declare a function which returns a struct*, with
the struct definition within the prototype?

For example, rather than the 16-element array of pointers to your
handler functions, each array element is a struct consisting of a
pointer to an int version of the function, and to a double version
of the function.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
R

Roberto Waltman

What is the purpose of the function pointer? Why do you need a pointer
to a function. I cannot really think of any application where this is
the only or even easiest solution to a problem.

Others already provided good answers. I thought a simple example would
complement them. A common use of function pointers is in table driven
command interpreters.
Let's say you need to write a CD player that is controlled by typing
commands such as "start", "next", etc.
The following could be the core of that program. Should be self
explanatory.

=================================

#include <stdio.h>
#include <string.h>

#define GOOD 1
#define BAD 0

void f_start (void);
void f_stop (void);
void f_pause (void);
void f_resume(void);
void f_next (void);
void f_prev (void);


struct cmd_row
{
char *cmd; /* command name */
char *help; /* command description */
void (*func)(void);/* function to call */
};


struct cmd_row cmd_table[] =
{
{"start", "start playback", f_start },
{"stop", "stop playback", f_stop },
{"pause", "pause playback", f_pause },
{"resume", "resume playback",f_resume},
{"next", "next track", f_next },
{"prev", "previous track", f_prev },
{NULL, NULL, NULL }
};


int cmd_run(char *cmd)
{
struct cmd_row *row = cmd_table;

if (!cmd)
{
return BAD;
}

while (row->cmd)
{
if (!strcmp(cmd, row->cmd))
{
puts(row->help);
(row->func)();
return GOOD;
}
row++;
}
return BAD;
}

=================================
 
F

Frederick Gotham

Kenneth Brody posted:
How about some sort of "runtime-programmable calculator". [...]
int (*(*RetrieveOperations(void(*pCallback)(int)))[16])(int,int)
[...]

You forgot to mention that there are 4 modes of this calculator,
and therefore it needs to return an array of 4 pointers to these
16-element arrays.



Of course, how negligent of me! Please accept my sincerest apologies.
Here's the updated code as requested ; )


/* Let's start off with an actual function */

#include <stdio.h>

int Addition(int const a, int const b)
{
int result = a + b;

printf( "The addition of %i and %i yields: %i\n", a, b, result );

return result;
}


/* Here's the callback function which gets invoked to
inform us of the database's current status. */


void Indicate(int) {}


/* Here's the function which accesses the database and retrieves
our mathematical operations as pointers to functions. */


int (*(*RetrieveOperations(void(*pCallback)(int)))[16])(int,int)
{
pCallback(0);

static int (*array[16])(int,int) =
{ Addition, Addition, Addition, Addition, Addition, Addition,
Addition, Addition, Addition, Addition, Addition, Addition,
Addition, Addition, Addition, Addition };

pCallback(1);

return &array;
}


/* Here's the function which retrieves four modes. */


int (*(*(*RetrieveFourModes(void(*pCallback)(int)))[4])[16])(int,int)
{
static int (*(*array[4])[16])(int,int);

*array = RetrieveOperations( Indicate );
array[1] = RetrieveOperations( Indicate );
array[2] = RetrieveOperations( Indicate );
array[3] = RetrieveOperations( Indicate );

return &array;
}

int main(void)
{
int (*(*(*p_array)[4])[16])(int,int) = RetrieveFourModes(Indicate);


/* Now let's call a few functions */


(*((*p_array)[0]))[15](1,2);
(*((*p_array)[1]))[14](7,3);
(*((*p_array)[2]))[13](55,8);
(*((*p_array)[3]))[12](1045,87);
}
 
B

Ben C

What is the purpose of the function pointer? Why do you need a pointer
to a function. I cannot really think of any application where this is
the only or even easiest solution to a problem.

Others already provided good answers. I thought a simple example would
complement them. A common use of function pointers is in table driven
command interpreters.
Let's say you need to write a CD player that is controlled by typing
commands such as "start", "next", etc.
The following could be the core of that program. Should be self
explanatory.

=================================

#include <stdio.h>
#include <string.h>

#define GOOD 1
#define BAD 0

void f_start (void);
void f_stop (void);
void f_pause (void);
void f_resume(void);
void f_next (void);
void f_prev (void);


struct cmd_row
{
char *cmd; /* command name */
char *help; /* command description */
void (*func)(void);/* function to call */
};


struct cmd_row cmd_table[] =
{
{"start", "start playback", f_start },
{"stop", "stop playback", f_stop },
{"pause", "pause playback", f_pause },
{"resume", "resume playback",f_resume},
{"next", "next track", f_next },
{"prev", "previous track", f_prev },
{NULL, NULL, NULL }
};


int cmd_run(char *cmd)
{
struct cmd_row *row = cmd_table;

if (!cmd)
{
return BAD;
}

while (row->cmd)
{
if (!strcmp(cmd, row->cmd))
{
puts(row->help);
(row->func)();
return GOOD;
}
row++;
}
return BAD;
}

This is a good example also of "data driven programming"-- try writing
this program without the function pointers and you probably end up with
a lot of conditions or switch statements.

I've seen some programs in which switch statements got really out of
hand. Use of function pointer tables is often an option for tidying them
up.

It's probably more efficient too:

If you write:

switch (state)
{
case SOMETHING:
do_something();
...
break
case BLAHBLAH:
do_something_else();
...
break
case ...

... lots and lots more case statements ...

the compiled program has to test the value of state against SOMETHING,
BLAHBLAH, and all the other labels, until it finds a match. If there are
a lot of labels this can be significant-- it is effectively a linear
search for the bit of code to execute. I suppose there's nothing
stopping the compiler building some sort of index for switch statements
with large numbers of cases, although I don't know if they do.

If you use:

fn = functions[state];
(*fn)();

on the other hand, fn is looked up at once by using state as an index.
 
A

Al Balmer

the compiled program has to test the value of state against SOMETHING,
BLAHBLAH, and all the other labels, until it finds a match. If there are
a lot of labels this can be significant-- it is effectively a linear
search for the bit of code to execute. I suppose there's nothing
stopping the compiler building some sort of index for switch statements
with large numbers of cases, although I don't know if they do.
They do :) In fact, they can be downright clever about it, especially
when the case values are non-contiguous.
If you use:

fn = functions[state];
(*fn)();

on the other hand, fn is looked up at once by using state as an index.

Works well if the range of state values isn't too great. If they're
non-contiguous, you can set missing ones to NULL and test before
calling.

The best part is that generally the code becomes easier to read.
 
T

Tom Plunket

Ben said:
This is a good example also of "data driven programming"-- try writing
this program without the function pointers and you probably end up with
a lot of conditions or switch statements.

I'd call it "table-oriented programming," if I wasn't afraid of
invoking TopMind. Maybe he doesn't hang out here though...

Building tables of homogenous data is incredibly useful, IMHO. Keeping
the data separate from the code is very important, and table-oriented
programming facilitates a large class of problems relating to that.

-tom!
 
B

Barry Schwarz

Kenneth Brody said:



Ctrl-Alt-Del to begin, Start to finish, and now Enter to exit. Got to love
Windows.

Unix isn't much better. The rename command is mv; the block
read/write command is dd, and one edit command is vi.


Remove del for email
 
A

Andrew Poelstra

Unix isn't much better. The rename command is mv; the block
read/write command is dd, and one edit command is vi.

Those aren't counter-intuitive. Renaming a file is essentially giving it
a different address. A change-of-address is usually a MoVe. And if you
don't want to use a line editor, try the VIsual editor.

I can't justify dd, other than to say that it's a very powerful tool,
and can be used for more that "Block Reader/Writer" would encompass.
 
I

Ian Collins

Andrew said:
Those aren't counter-intuitive. Renaming a file is essentially giving it
a different address. A change-of-address is usually a MoVe. And if you
don't want to use a line editor, try the VIsual editor.
The commands are probably this verbose because there were more than 26,
so two characters had to be used :)
 
R

Richard Bos

Andrew Poelstra said:
Those aren't counter-intuitive. Renaming a file is essentially giving it
a different address.

No, it's giving it a different name. AFAIAA, the inode doesn't even
change.
A change-of-address is usually a MoVe.

True, but irrelevant to renaming. If I remove the slice of pine saying
"Dunroamin" in a brush letter from my house, and put in its place a
faux-stone plaque saying "RLB MANSION" in faux-chiseled quadrata, I do
not need to pack up the plates.
And if you don't want to use a line editor, try the VIsual editor.

I'd rather use a real editor, but that's another issue.

Richard
 
K

Kenneth Brody

Richard said:
No, it's giving it a different name. AFAIAA, the inode doesn't even
change.

It does if you move it to a different filesystem.
True, but irrelevant to renaming. If I remove the slice of pine saying
"Dunroamin" in a brush letter from my house, and put in its place a
faux-stone plaque saying "RLB MANSION" in faux-chiseled quadrata, I do
not need to pack up the plates.

However, it's still a "move", and not a "rename" program. Yes, you
can move it to a new name in the same directory, which is the same
effect as a rename, but that's just coincidental.
I'd rather use a real editor, but that's another issue.

I forget if it was here or elsewhere, but I saw someone point out
(related to the recent "6/6/6" date) that "vi vi vi" is "the editor
of the beast".

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
A

Andrew Poelstra

No, it's giving it a different name. AFAIAA, the inode doesn't even
change.

If you're sending a letter to someone, you use their address. If you're
sending data to a file, you use its name. You don't use the inode. For
all you care (assuming you aren't a filesystem designer), the inode itself
could be metaphysical, and could be changing position with every heartbeat
of the universe.

(My point is that a filename is more analogous to an address than an inode
is.)

Another justification for mv is that /actually/ moving the file (that is,
to another directory) is just as complex as changing the name; instead,
you edit the inode tables of two directories. This is no more a move than
renaming is.
True, but irrelevant to renaming. If I remove the slice of pine saying
"Dunroamin" in a brush letter from my house, and put in its place a
faux-stone plaque saying "RLB MANSION" in faux-chiseled quadrata, I do
not need to pack up the plates.

Unless you are lying, you will indeed need to move that wine from RLB
MANSION. If your guests ask for some RLB, and you give them what clearly
tastes like Dunroamin, they won't be very happy.
I'd rather use a real editor, but that's another issue.

I hope you mean emacs or some other great editor, because I've spent all
day arguing with people promoting the merits of M$ notepad. I personally
like vi, but that's hardly a holy war I want to fight.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,181
Messages
2,570,970
Members
47,537
Latest member
BellCorone

Latest Threads

Top