typedef int intfunc(int);/* int-et visszaado, 1 int-et varo * * fuggvenytipus */ typedef intfunc *fad; /* intfunc tipusu tarolasi egy- * * segre mutato tipus */A fent definiált intfunc típust felhasználhatjuk a majdan meghívandó egyes függvények elõzetes deklarálására.
A végrehajtandó függvényen kívül egy menüpont fontos jellemzõje az illetõ menüpont neve (azonosító szövege), az a nyomtatható karakter, amivel Enter megnyomása helyett kiválasztható a menüpont. Célszerû megengednünk, hogy a menüpont által meghívandó függvénynek egy, a menüpont leírásában tárolt paramétert is átadjunk. Ha a menürendszerünkhöz alkalmas help-rendszert is szeretnénk, célszerû az egyes menüpontokhoz rendelt help-szövegre utaló információt (például egy file-indexet) is tárolni. Ezeket az informáiókat - a menüponthoz rendelt függvény címével együtt - az alább deklarált menuitem (menüpont) struktúrába szerveztük:
typedef struct { char *text; /* A menupont azonosito szovege */ char key; /* A menupontot kivalaszto betu */ int helpindex; /* A menuponthoz rendelt help-kod */ fad function; /* A menuponthoz tartozo fv-re mutat */ int param; /* A '*function' fuggveny parametere */ } menuitem;A figyeljük meg, hogy a fenti struktúra definicóból kimaradt a típuscímke, hiszen typedef-fel eleve azonosítót rendelünk hozzá - rekurzív adatdefinicóról pedig szó sincs.
Most lássuk, hogy szervezhetünk egy menüt a fenti módon deklarált menuitem struktúrák segítségével.
A menüpontjainkat célszerûen egy menuitem típusú tömbben tároljuk, amelynek méretét is tudnunk kell. A menü tartalma mellett fontos annak megjelenése is. Szükségünk lehet arra, hogy a menüt keretezõ doboz tetején esetleg egy menünevet, egy fejlécet (header-t) is megjelenítsünk. Fontos azt is tudnunk, hogy melyik x-y karakterpozicióba kerül a menüdoboz (annak például a bal felsõ sarka) a képernyõn, és az is lényeges információ, hogy hány karakterpoziciót foglal le a menüdoboz vízszintes és függõleges irányban. Azt is nyilvántarthatjuk egy menürõl, hogy melyik menüpontot választottuk ki benne utoljára és fontos lehet az is, hogy az adott menü hol helyezkedik el egy hierarchikus menü-fán. Ezeket az információkat foglaltuk egybe az alábbi menutype struktúrában:
typedef struct { char *header; /* A menu fejlecszovegere mutat */ int x; /* A menudoboz bal felso sarkanak */ int y; /* x es y koordinatai, valamint */ int xs; /* a menudoboz x es */ int ys; /* y iranyu merete. */ int itemno; /* A menupontok szama */ menuitem *items; /* A menupontok listajara mutat. */ int hierarch; /* Ha 1, kozvetlenul a fomenu hivja */ int lastitem; /* Utoljara kivalasztott pont szama */ } menutype;A menuitem típusból egy-egy inicializált tömböt szervezve hozhatjuk létre az egyes menük tartalmára vonatkozó adathalmazt. Egy ilyen lista kezdõcíme kerül egy menutype struktúra items mezõjébe. Egy-egy menutype struktúra egy komplett menü leírását tartalmazza. Ezekbõl a struktúrákból szintén egy tömböt szervezünk, ez lesz a menus tömb. E tömb elsõ néhány eleme egy-egy menüfa gyökerét (azaz a fõmenü egyes pontjaiként aktivizálandó menüket) reprezentálja, a többi elem pedig az egyes fákra felfûzött almenüket írja le. Tekintsük át tehát a teljes menürendszert definiáló adatstruktúrát:
/* Kulso fuggvenyek deklaracioja */ extern intfunc data, r_data, w_data, statf, regr, linf, barf, save, load; /* A a menukezelo fuggveny prototipus erteku deklaracioja */ intfunc menu; /* Elore hivatkozashoz */ intfunc dir, shell; /* Tovabbi fv-ek elore hivatkozshoz */ /* Az egyes menulistak (items_0 .. items_3) es a menuk: */ menuitem items_0[ ] = { /* text key hlp func. param. */ "Directory", 'D', 1, dir, 0, "Os shell", 'O', 2, shell, 0, "File", 'F', 3, menu, 3,/*a 3.sz. menu almenu lesz */ exitxt, 'X',-1, NULL, 0 /*-1-es parameter: exit */ }; /* Tombmeret: */ #define N0 sizeof(items_0)/sizeof(menuitem) menuitem items_1[ ] = { "Default", 'D', 4, data, 7, "Read data", 'R', 5, r_data,1, "List data", 'L', 6, w_data,2, "Statistics",'S', 7, statf, 3, exitxt, 'X',-1, NULL, 0 }; #define N1 sizeof(items_1)/sizeof(menuitem) menuitem items_2[ ] = { "Regression",'R', 8, regr, 4, "Plot", 'P', 9, linf, 5, "Bar", 'B',10, barf, 6, exitxt, 'X',-1, NULL, 0 }; #define N2 sizeof(items_2)/sizeof(menuitem) menuitem items_3[ ] = { "Save", 'S',11, savef, 0, "Load", 'L',12, loadf, 0, exitxt, 'X',-1, NULL, 0 }; #define N3 sizeof(items_3)/sizeof(menuitem) /* A teljes menurendszer leirasa: */ menutype menus[ ] = {/* head. x y xs ys itemno items hier. last */ "", 9, 2, 13, N0+3, N0, items_0, 1, 0, "", 35, 2, 14, N1+3, N1, items_1, 1, 0, "", 61, 2, 14, N2+3, N2, items_2, 1, 0, "Files",11, 6, 8, N3+3, N3, items_3, 0, 1 };Figyeljük meg, hogy a menülisták méretének meghatározását a fordító programra bíztuk: a sizeof operátor segítségével megkapjuk mind az egyes menülistákat tartalmazó tömbök helyfoglalását byte-okban, mind a menuitem típus méretét; ezek hányadosa adja meg a menülista tömbök logikai méretét (azaz azt, hogy hány elemû egy menülista). Ezeket a kifejezéseket #define makróként definiáljuk, és az így kapott kifejezéseket használjuk fel a menus tömb inicializálására. Ez egy igen flexibilis megoldás, ugyanis egy menülista bõvítése során a menus tömb inicializálásakor a menüdoboz méretére és a menülista hosszára vonatkozóan automatikusan helyes adatot fog a fordító felhasználni. A menus tömb kitöltését legfeljebb csak akkor kell módosítani, ha egy új menülista-elem hossza nagyobb, mint az adott menüdobozhoz megadott xs érték.