[comp.lang.c] Functions within structures

mdb@abcom.ATT.COM (5013 ) (11/07/90)

Hi, netlanders,
 
   I need help.  I am building a menu using structures and would like
   to be able to include the function to be run within the structure.
 
   Below is an example of what I would like to do.
===========================================================================
/****************************************************************************
**
**      Program     : CH10.c
**      Author      : Michael D. Barnes
**      Date Created: November 04, 1990
**      Date Revised:
**      Notes       : This database manager will:
**
**                        ADD RECORD
**                        FIND RECORD
**                        QUIT
**
**      Globals used: MENU_ITEM -> Number of items in menu
**                    MAX_RECS  -> Maximum Records in database allowed
**                    sorted    -> Does database need to be sorted?
**                    phone_bk  -> structure phone book data record
**                    menu      -> structure menu data record
**
****************************************************************************/
 
#include <stdio.h>
#include <conio.h>
#include <bios.h>
#include <ctype.h>
 
#define MENU_ITEM 2
#define MAX_RECS  6
 
int   add_rec();
int   find_rec();
int   quit();
 
unsigned	int	records=0;
typedef struct {
   char    key;
   int     x_row;
   int     y_row;
   char    msg[20];
} MENU;
 
MENU menu[MENU_ITEM+1] = {
    { '1',7,25,"Add Phone Number",add_rec() },
    { '2',9,25,"Find Phone number",find_rec() },
    { 'Q',12,25,"QUIT",quit() }
    } ;
 
int menu_cnt=MENU_ITEM;        /* What menu option is used */
 
main(void)
{
 
int   menu_opt;
disp_menu(menu,menu_cnt);
 
while ( 1 )
{
 
menu_opt = select();
(*(menu[menu_opt].foo))();
    gotoxy ( menu[menu_cnt].y_row,menu[menu_cnt].x_row );
    printf ( "%c. %s",menu[menu_cnt].key,menu[menu_cnt].msg );
    gotoxy ( menu[menu_cnt].y_row,menu[menu_cnt].x_row );
}
}
=======================================================================
Now, how do I assigned these functions to the structure (or is it posible)
and then access these same functions?  Any help will be greatly appreciated.
 
 

			Thank for yor help in advance

			Mike Barnes
			(415) 224-3030

hagins@gamecock.rtp.dg.com (Jody Hagins) (11/08/90)

First off, this sounds like a class project, but since you
are not asking for a program, but specific help, I consider
this to be fine since you could find this in any C book.
I used to teach, and I would not have a problem with this type
of assistance.


In article <2203@abcom.ATT.COM>, mdb@abcom.ATT.COM (5013 ) writes:
|> Hi, netlanders,
|>  
|>    I need help.  I am building a menu using structures and would like
|>    to be able to include the function to be run within the structure.
|>  
|>    Below is an example of what I would like to do.
|> ===========================================================================
|> /****************************************************************************
|> **
|> **      Program     : CH10.c
|> **      Author      : Michael D. Barnes
|> **      Date Created: November 04, 1990
|> **      Date Revised:
|> **      Notes       : This database manager will:
|> **
|> **                        ADD RECORD
|> **                        FIND RECORD
|> **                        QUIT
|> **
|> **      Globals used: MENU_ITEM -> Number of items in menu
|> **                    MAX_RECS  -> Maximum Records in database allowed
|> **                    sorted    -> Does database need to be sorted?
|> **                    phone_bk  -> structure phone book data record
|> **                    menu      -> structure menu data record
|> **
|> ****************************************************************************/
|>  
|> #include <stdio.h>
|> #include <conio.h>
|> #include <bios.h>
|> #include <ctype.h>
|>  
|> #define MENU_ITEM 2
|> #define MAX_RECS  6
|>  
|> int   add_rec();
|> int   find_rec();
|> int   quit();
|>  
|> unsigned	int	records=0;
|> typedef struct {
|>    char    key;
|>    int     x_row;
|>    int     y_row;
|>    char    msg[20];


      int     (*foo)();		/* You need to have this field */


|> } MENU;
|>  
|> MENU menu[MENU_ITEM+1] = {
|>     { '1',7,25,"Add Phone Number",add_rec() },
|>     { '2',9,25,"Find Phone number",find_rec() },
|>     { 'Q',12,25,"QUIT",quit() }
|>     } ;


Remove the ()'s from the above assignments of add_rec(), find_rec(),
and quit().


|>  
|> int menu_cnt=MENU_ITEM;        /* What menu option is used */
|>  
|> main(void)
|> {
|>  
|> int   menu_opt;
|> disp_menu(menu,menu_cnt);
|>  
|> while ( 1 )
|> {
|>  
|> menu_opt = select();
|> (*(menu[menu_opt].foo))();


This should work now.  However, keep in mind that menu[menu_opt].foo
is a pointer to a function of type int.  Don't try to mix
function pointer types.  Also, remember that you need to pass parms
in the ()'s if they are needed.


|>     gotoxy ( menu[menu_cnt].y_row,menu[menu_cnt].x_row );
|>     printf ( "%c. %s",menu[menu_cnt].key,menu[menu_cnt].msg );
|>     gotoxy ( menu[menu_cnt].y_row,menu[menu_cnt].x_row );
|> }
|> }
|> =======================================================================
|> Now, how do I assigned these functions to the structure (or is it posible)
|> and then access these same functions?  Any help will be greatly appreciated.
|>  
|>  
|> 
|> 			Thank for yor help in advance
|> 
|> 			Mike Barnes
|> 			(415) 224-3030

gwyn@smoke.brl.mil (Doug Gwyn) (11/09/90)

In article <2203@abcom.ATT.COM> mdb@abcom.ATT.COM (5013 ) writes:
-> int   add_rec();
-> int   find_rec();
-> int   quit();
-> unsigned	int	records=0;
-> typedef struct {
->    char    key;
->    int     x_row;
->    int     y_row;
->    char    msg[20];
	int	(*foo)();	/* ADD THIS MEMBER */
-> } MENU;
-> MENU menu[MENU_ITEM+1] = {
->     { '1',7,25,"Add Phone Number",add_rec() },
	/* CHANGE THE ABOVE TO: */
	{ '1', 7, 25, "Add phone number", add_rec },
[...]
->     } ;
[...]
-> menu_opt = select();
-> (*(menu[menu_opt].foo))();
/* That's okay although excessively parenthesized. */

wallace@ynotme.enet.dec.com (Ray Wallace) (11/10/90)

In article <2203@abcom.ATT.COM>, mdb@abcom.ATT.COM (5013 ) writes...
>   I need help.  I am building a menu using structures and would like
>   to be able to include the function to be run within the structure.
Change your menu structure to have -
    void    (*foo)();		/* Pointer to a function returning void */

Change your function call to -
   menu[menu_opt].foo();

---
Ray Wallace		
		(INTERNET,UUCP) wallace@oldtmr.enet.dec.com
		(UUCP)		...!decwrl!oldtmr.enet!wallace
		(INTERNET)	wallace%oldtmr.enet@decwrl.dec.com
---

john@chinet.chi.il.us (John Mundt) (11/10/90)

In article <2203@abcom.ATT.COM> mdb@abcom.ATT.COM (5013 ) writes:
>   I need help.  I am building a menu using structures and would like
>   to be able to include the function to be run within the structure.

	....

> 
>int   add_rec();
>int   find_rec();
>int   quit();
> 
>unsigned	int	records=0;
>typedef struct {
>   char    key;
>   int     x_row;
>   int     y_row;
>   char    msg[20];
    int (*fptr)();	/* add this to your structure prototype */
>} MENU;
> 
>MENU menu[MENU_ITEM+1] = {
>    { '1',7,25,"Add Phone Number",add_rec },
>    { '2',9,25,"Find Phone number",find_rec },
>    { 'Q',12,25,"QUIT",quit }
>    } ;

Notice that the ()'s were removed from the functions.

> 
>Now, how do I assigned these functions to the structure (or is it posible)
>and then access these same functions?  Any help will be greatly appreciated.

The functions are now assigned, so that menu[whatever].fptr is the
function.  You can use the function thusly,

	{
		int some_value;
		some_value = (*menu[whatever].fptr)();
	}

since menu[whatever].fptr is the address of the function, and
*menu[whatever].fptr is the function.  K&R says it better.

Lint and/or your compiler may or may not complain about this.  Seems
to depend on the machine.  3b2's like it, 3b1's do not.  386's don't
like it, but in all cases it works.  

As an aside,

		some_value = (*menu[whatever].fptr)();
		some_value = (menu[whatever].fptr)();

produce the same assembler code on at least one machine, and both
work, though the first one is the one that is considered correct.
-- 
---------------------
john@admctr.chi.il.us
John Mundt   Teachers' Aide, Inc.  P.O. Box 1666,  Highland Park, IL
(708) 998-5007 || -432-8860 

gwyn@smoke.brl.mil (Doug Gwyn) (11/12/90)

In article <1990Nov10.155153.20639@chinet.chi.il.us> john@chinet.chi.il.us (John Mundt) writes:
>		some_value = (*menu[whatever].fptr)();
>		some_value = (menu[whatever].fptr)();
>produce the same assembler code on at least one machine, and both
>work, though the first one is the one that is considered correct.

Actually the second one is more "theoretically" correct.  The function
designator in the first expression is automatically converted to a
pointer to the function; the second form is already that way.

scjones@thor.UUCP (Larry Jones) (11/14/90)

In article <14431@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) writes:
> [ about whether "(*pf)() or (pf)() is more correct ]
> 
> Actually the second one is more "theoretically" correct.  The function
> designator in the first expression is automatically converted to a
> pointer to the function; the second form is already that way.

That depends on which theory you subscribe to.  In classic C, you called
a function -- there was no automatic conversion to a pointer -- and the
first form was thus "theoretically" correct.  The second form was, at
least for some compilers, "completely" wrong -- they refused to generate
code when presented with that construct.

Of course, we all know that you use the address to call a function so
it makes much more sense to say that a call is made using a pointer to
the function and having the name of a function decay into a function
pointer like the name of an array decays into a pointer to the first
element.  That's precisely what X3J11 did, although both decays were
generalize to expressions of the specified type rather than special
casing names.
----
Larry Jones                         UUCP: uunet!sdrc!thor!scjones
SDRC                                      scjones@thor.UUCP
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
Don't you hate it when your boogers freeze? -- Calvin