Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
92
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Special Pointers and Their Use

C C C

 

C4C

 

C C C

 

C

The program FUNPTR.C, in Listing 4.3, has an example of one use of function pointers. This program calls a different function for each character in an input string. Although initializing the array of function pointers may take some time (and effort) in most programs, this time factor is not as significant as the effort to program separate calls, even if the separate calls are in a function by themselves.

Listing 4.3. FUNPTR.C.

/* FUNPTR, written 22 May 1992 by Peter D. Hipson */ /* An array of function pointers. */

#include

<stdio.h>

// Make includes first part of file

#include

<string.h>

// For string functions.

#include

<stdlib.h>

// Standard include items.

#include

<process.h> // For exit() etc.

int main(

// Define main() and the fact that this program uses

int

argc,

// the passed parameters.

char

*argv[],

 

 

char

*envp[]

 

 

);

 

 

 

void NonPrint(const char

chChar);

void Letter(const char

chChar);

void Number(const char

chChar);

void Space(const char

chChar);

int main(

 

 

int

argc,

 

 

char

*argv[],

 

 

char

*envp[]

 

 

)

 

 

 

{

 

 

 

void

(*function[256])(const char);

char

*pszTemp;

 

 

char

szBuffer[512];

// Your input buffer.

continues

115

Part I • Honing Your C Skills

Listing 4.3. continued

int i;

/* First initialize your array of function pointers. Notice that,

*because you have specified what the function pointed to by this

*pointer requires for a parameter, all the functions assigned to

*this array require the same number and types of parameters.

*The parameters could have been omitted, but then you don't

*benefit from type checking on parameters. */

for (i = 0; i < 256; i++)

{

if ((unsigned char)i < ' ')

{

function[i] = NonPrint;

}

else

{

if ((unsigned char)i >= '0' && (unsigned char)i <= '9')

{

function[i] = Number;

}

else

{

if ((unsigned char)i == ' ')

{

function[i] = Space;

}

else

{

function[i] = Letter;

}

}

}

}

while (gets(szBuffer))

{

for (i = 0; szBuffer[i]; i++)

116

Special Pointers and Their Use

 

{

 

 

/*

Now, this is nice syntax:

*/

 

function[(int)szBuffer[i]] (szBuffer[i]);

 

 

}

 

 

 

}

 

 

 

return(0);

 

 

}

 

 

 

void NonPrint(

 

 

 

const char

chChar)

 

{

 

 

 

/*

Make it printable by adding a '@' to it.*/

 

 

printf("CTRL -

'%c'\n", chChar + '@');

 

}

 

 

 

void Space(

 

 

 

const char

chChar)

 

{

 

 

 

 

printf("Space

'%c'\n", chChar);

 

}

 

 

 

void Letter(

 

 

 

const char

chChar)

 

{

 

 

 

 

printf("Letter

'%c'\n", chChar);

 

}

 

 

 

void Number(

 

 

 

const char

chChar)

 

{

 

 

 

 

printf("Number

'%c'\n", chChar);

 

}

 

 

 

C C C

C4C C

C C C

117

Part I • Honing Your C Skills

(Remember, I didn’t promise that FUNPTR does anything significant.)

I’ve shown that function prototypes are important, but, in a program that is using function pointers, they are vital. Notice that each of the functions that will be assigned to the function pointer has identical prototypes—their return types are the same and their parameters match equally.

Let’s look at some of the fun parts of FUNPTR. The declaration of the array of function pointers has a number of critical parts:

void

(*function[256])(const char);

The void tells C that these functions don’t return anything. If the functions return a value, use that value’s type. Because the order and positioning of the parentheses are critical, the name of the function pointer is next. If this were not an array declaration, the declaration would be

void

(*function)(const char);

Following the function pointer name are the function’s parameters (again, the parentheses are important). Keep it simple—try to avoid having functions assigned that take different types or counts of parameters. Having functions with different parameters weakens the compiler’s capability to check for errors, although it is possible.

After declaring the function pointer array, you initialize it. When you assign a function’s address to a function pointer, do not use the function’s parentheses.

for (i = 0; i < 256; i++)

{

if ((unsigned char)i < ' ')

{

function[i] = NonPrint; /* NOTICE: No (), just the name */

}

else

{

if ((unsigned char)i >= '0' && (unsigned char)i <= '9')

{

function[i] = Number; /* NOTICE: No (), just the name */

}

else

{

if ((unsigned char)i == ' ')

118

Special Pointers and Their Use

C C C

 

C4C

 

C C C

 

C

{

function[i] = Space; /* NOTICE: No (), just the name */

}

else

{

function[i] = Letter; /* NOTICE: No (), just the name */

}

}

}

}

Because FUNPTR has an array of 256 possible functions to call, you initialize all of them. Because you potentially call a different function for each of the possible 256 characters in the character set and because (with a few exceptions) the user can enter any character, you must make sure that all the members of the function pointer array are initialized.

After you have initialized the function pointer array, you can continue with the rest of the program. Use a simple loop to get a line from the keyboard, and then for each character in the line, call the appropriate function:

 

while (gets(szBuffer))

 

 

{

 

 

for (i = 0; szBuffer[i]; i++)

 

 

{

 

/*

Now, this is nice syntax:

*/

 

function[(int)szBuffer[i]] (szBuffer[i]);

 

 

}

 

 

}

 

Notice the strange call function[]() (using an array of function pointers doesn’t always look good). It eliminates a large if()...else block that saves valuable programming time if this letter-by-letter parsing of the string is done often (more than once) in a program. A second important factor is that the while() loop runs faster because many if() statements are eliminated.

Using a function pointer as a parameter in a function call is not unusual. As mentioned, the library function qsort() does this.

Look at the following prototype for qsort(). The prototype is in the standard header file stdlib.h and in search.h, if your compiler has such a header file.

119

Part I • Honing Your C Skills

void _FAR_ __cdecl qsort(

void _FAR_ *,

/* array to be sorted */

 

size_t,

/* number of elements in

the array */

size_t,

/* size of each array element */

int (_FAR_ __cdecl *)(const void _FAR_ *, const void _FAR_ *));

qsort()’s first three parameters are as expected: an array pointer, two integers showing the number of elements in the array, and the size of the elements.

The final parameter in the call to qsort() is the most interesting one. It specifies that the parameter is the address of a function that returns an int value and takes two far pointers. Both of these pointers are declared as type void so that any type of pointer can be passed; the function being called, however, must know the pointer’s type. Because each call to qsort() is generally for a specific type of array, the function being called will know about the array’s types. qsort() is discussed in detail in Chapter 10, “Data Management: Sorts, Lists, and Indexes.”

Menus and Pointers

Peter’s programming rule number 6: Don’t reinvent the wheel. OK, it’s not an original rule, but even with Peter’s rules, I didn’t want to reinvent the rule.

There are several easy ways to put menus in a program without writing them all yourself. The first and by far the best is to use Windows. No kidding, Windows is an effective way to create slick user interfaces. Don’t be put off by the learning curve of Window’s programming—it is much less than writing the user interface yourself.

If you are determined not to use Windows, systems are available that enable almost any type of program to have extensive menu support, such as pull-down menus, pop-up dialog menus, and so on.

It’s well beyond the scope of this book to write an entire pull-down menu system. One simple text-only system requires many thousands of lines of code. This book can, however, cover many of the basics.

A pull-down menu might, for example, call a different function for each of the menu items. The function call to the menu system might include such parameters as an array for each menu item’s text and an array of function pointers to call for each menu item.

120

Special Pointers and Their Use

C C C

 

C4C

 

C C C

 

C

You can look at the top bar menu separately and use a rather simple call to a function such as getch() to process the keystrokes entered. Part of MENU1.C assumes that the program is running under DOS on a PC, that the ANSI.SYS device driver (used for screen control) is installed, and that the compiler supports the functions this program calls.

In Listing 4.4, the program MENU1.C implements a simple pull-down menu that has a simple dialog box to enable the user to enter a filename.

Listing 4.4.MENU1.C.

/* MENU1, written 23 May 1992 by Peter D. Hipson */ /* A simple menu program. */

/* This program assumes and uses Microsoft's extensions to C.

*Readers with other compilers may have to change the program

*to use the calls that their compiler supplies to perform

*the same functions. */

#include <stdio.h>

 

// Make includes first part of file

#include <string.h>

// For

string functions.

#include <stdlib.h>

// Standard include items.

#include <process.h>

// For

exit(), etc.

#include <conio.h>

 

// For

getch() and other console I/O.

#include <ctype.h>

 

// For

char functions (_toupper()...)

/* ANSI.SYS screen control #define's below:

*/

 

 

 

#define BOLD

"\x1B[1m"

 

#define NORMAL

"\x1B[0m"

 

#define RED

"\x1B[31m"

 

#define BLACK

"\x1B[30m"

 

#define GREEN

"\x1B[32m"

 

#define CLEAR_SCREEN

"\x1B[2J"

#define CLEAR_EOL

 

"\x1B[K"

#define MOVE_CURSOR

"\x1B[%d;%df"

continues

121

Part I • Honing Your C Skills

Listing 4.4.continued

char szTopBar[] = {/* Must be 80 characters long MAX. */ CLEAR_SCREEN

BOLD"F"NORMAL"iles "

BOLD"E"NORMAL"dit "

BOLD"V"NORMAL"iew "

BOLD"P"NORMAL"roject "

BOLD"R"NORMAL"un "

BOLD"D"NORMAL"ebug " CLEAR_EOL

};

/* Line-drawing characters for the PC = " "*/

void

 

 

 

 

MenuBar(); /* Never called! Make the array look good. */

char

 

 

 

 

*szFiles[] = {

 

"

 

 

 

 

",

 

"

 

"BOLD"N"NORMAL"ew

",

"

 

"BOLD"O"NORMAL"pen

",

 

"

 

 

"BOLD"C"NORMAL"lose

",

 

 

"

 

 

"BOLD"S"NORMAL"ave

",

 

 

"

 

 

save "BOLD"A"NORMAL"s

",

 

 

"

 

 

 

 

 

 

 

 

",

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

"

 

 

 

 

 

"BOLD"P"NORMAL"rint

",

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

"

 

 

 

ДДДДДДДДДДДДДДД´",

 

 

 

 

"

 

 

 

 

 

 

 

 

",

e"BOLD"X"NORMAL"it

"

 

 

 

 

 

 

 

 

 

",

 

 

 

 

 

 

 

 

 

 

 

NULL};

 

void

 

 

 

 

DoFilesNew();

 

void

 

 

 

 

DoFilesOpen();

 

void

 

 

 

 

DoFilesClose();

 

void

 

 

 

 

DoFilesSave();

 

void

 

 

 

 

DoFilesSaveAs();

 

void

 

 

 

 

DoFilesPrint();

 

void

 

 

 

 

DoFilesEXit();

 

122

 

 

Special Pointers and Their Use

C C C

 

 

 

C4C

 

 

 

C C C

void

(*FilesFunctions[])(void) = {

C

 

 

MenuBar,

 

 

DoFilesNew,

 

 

DoFilesOpen,

 

 

DoFilesClose,

 

 

DoFilesSave,

 

 

DoFilesSaveAs,

 

 

MenuBar,

 

 

DoFilesPrint,

 

 

MenuBar,

 

 

DoFilesEXit,

 

 

MenuBar,

 

 

NULL

 

 

 

};

 

 

int main(

// Define main() and the fact that this program uses

 

int

argc, // the passed parameters.

 

 

char

*argv[],

 

 

char

*envp[]

 

 

);

 

 

void PullDown(char **, int, void (__cdecl **)(void));

 

int main(

 

 

 

int

argc,

 

 

char

*argv[],

 

 

char

*envp[]

 

 

)

 

 

{

char chEntered;

while (1)

{

printf(szTopBar);

chEntered = (char)getch();

continues

123

Part I • Honing Your C Skills

Listing 4.4. continued

if (chEntered == '\0' || chEntered == '\xE0')

{// PC Extended character (function key etc.) chEntered = (char)getch();

}

printf(MOVE_CURSOR, 10, 10); /* Using printf() fully here! */

switch (_toupper((int)chEntered))

{

case 'F':

PullDown(szFiles, 1, FilesFunctions); break;

case 'E':

printf("Edit submenu called" CLEAR_EOL); break;

case 'V':

printf("View submenu called" CLEAR_EOL); break;

case 'P':

printf("Project submenu called" CLEAR_EOL); break;

case 'R':

printf("Run submenu called" CLEAR_EOL); break;

case 'D':

printf("Debug submenu called" CLEAR_EOL); break;

default:

printf("Invalid key!" CLEAR_EOL); break;

}

}

124