Anda di halaman 1dari 5

3/29/13

Function Pointers in C and C++ - Cprogramming.com

Programs as Data: Function Pointers


A function pointer is a v ariable that stores the address of a function that can later be called through that function pointer. This is useful because functions encapsulate behav ior. For instance, ev ery tim e y ou need a particular behav ior such as drawing a line, instead of writing out a bunch of code, all y ou need to do is call the function. But som etim es y ou would like to choose different behav iors at different tim es in essentially the sam e piece of code. Read on for concrete exam ples.

By Alex Allain

Example Uses of Function Pointers


Functions as Arguments to Other Functions
If y ou were to write a sort routine, y ou m ight want to allow the function's caller to choose the order in which the data is sorted; som e program m ers m ight need to sort the data in ascending order, others m ight prefer descending order while still others m ay want som ething sim ilar to but not quite like one of those choices. One way to let y our user specify what to do is to prov ide a flag as an argum ent to the function, but this is inflexible; the sort function allows only a fixed set of com parison ty pes (e.g., ascending and descending). A m uch nicer way of allowing the user to choose how to sort the data is sim ply to let the user pass in a function to the sort function. This function m ight take two pieces of data and perform a com parison on them . We'll look at the sy ntax for this in a bit.

Callback Functions
Another use for function pointers is setting up "listener" or "callback" functions that are inv oked when a particular ev ent happens. The function is called, and this notifies y our code that som ething of interest has taken place. Why would y ou ev er write code with callback functions? You often see it when writing code using som eone's library . One exam ple is when y ou're writing code for a graphical user interface (GUI). Most of the tim e, the user will interact with a loop that allows the m ouse pointer to m ov e and that redraws the interface. Som etim es, howev er, the user will click on a button or enter text into a field. These operations are "ev ents" that m ay require a response that y our program needs to handle. How can y our code know what's happening? Using Callback functions! The user's click should cause the interface to call a function that y ou wrote to handle the ev ent. To get a sense for when y ou m ight do this, consider what m ight happen if y ou were using a GUI library that had a "create_button" function. It m ight take the location where a button should appear on the screen, the text of the button, and a function to call when the button is clicked. Assum ing for the m om ent that C (and C+ + ) had a generic "function pointer" ty pe called function, this m ight look like this: v o i dc r e a t e _ b u t t o n (i n tx ,i n ty ,c o n s tc h a r* t e x t ,f u n c t i o nc a l l b a c k _ f u n c) ; Whenev er the button is clicked, callback_func will be inv oked. Exactly what callback_func does depends on the button; this is why allowing the create_button function to take a function pointer is useful.

Function Pointer Syntax


The sy ntax for declaring a function pointer m ight seem m essy at first, but in m ost cases it's really quite straightforward once y ou underst and what's going on. Let's look at a sim ple exam ple: v o i d( * f o o ) ( i n t ) ;

www.cprogramming.com/tutorial/function-pointers.html

1/5

3/29/13

Function Pointers in C and C++ - Cprogramming.com

In this exam ple, foo is a pointer to a function taking one argum ent, an integer, and that returns v oid. It's as if y ou're declaring a function called "*foo", which takes an int and returns v oid; now, if *foo is a function, then foo m ust be a pointer to a function. (Sim ilarly , a declaration like int *x can be read as *x is an int, so x m ust be a pointer to an int.) The key to writing the declaration for a function pointer is that y ou're just writing out the declaration of a function but with (*func_nam e) where y ou'd norm ally just put func_nam e.

Reading Function Pointer Declarations


Som etim es people get confused when m ore stars are thrown in: v o i d* ( * f o o ) ( i n t* ) ; Here, the key is to read inside-out; notice that the innerm ost elem ent of the expression is *foo, and that otherwise it looks like a norm al function declaration. *foo should refer to a function that returns a v oid * and takes an int *. Consequently , foo is a pointer to just such a function.

Initializing Function Pointers


To initialize a function pointer, y ou m ust giv e it the address of a function in y our program . The sy ntax is like any other v ariable: # i n c l u d e< s t d i o . h > v o i dm y _ i n t _ f u n c ( i n tx ) { p r i n t f (" % d \ n " ,x) ; } i n tm a i n ( ) { v o i d( * f o o ) ( i n t ) ; / *t h ea m p e r s a n di sa c t u a l l yo p t i o n a l* / f o o=& m y _ i n t _ f u n c ; r e t u r n0 ; } (Note: all exam ples are written to be com patible with both C and C+ + .)

Using a Function Pointer


To call the function pointed to by a function pointer, y ou treat the function pointer as though it were the nam e of the function y ou wish to call. The act of calling it perform s the dereference; there's no need to do it y ourself: # i n c l u d e< s t d i o . h > v o i dm y _ i n t _ f u n c ( i n tx ) { p r i n t f (" % d \ n " ,x) ; }

i n tm a i n ( ) { v o i d( * f o o ) ( i n t ) ; f o o=& m y _ i n t _ f u n c ; / *c a l lm y _ i n t _ f u n c( n o t et h a ty o ud on o tn e e dt ow r i t e( * f o o ) ( 2 ))* /
www.cprogramming.com/tutorial/function-pointers.html 2/5

3/29/13

Function Pointers in C and C++ - Cprogramming.com

f o o (2) ; / *b u ti fy o uw a n tt o ,y o um a y* / ( * f o o ) (2) ; r e t u r n0 ; } Note that function pointer sy ntax is flexible; it can either look like m ost other uses of pointers, with & and *, or y ou m ay om it that part of sy ntax. This is sim ilar to how array s are treated, where a bare array decay s to a pointer, but y ou m ay also prefix the array with & to request its address.

Function Pointers in the Wild


Let's go back to the sorting exam ple where I suggested using a function pointer to write a generic sorting routine where the exact order could be specified by the program m er calling the sorting function. It turns out that the C function qsort does just that. From the Linux m an pages, we hav e the following declaration for qsort (from stdlib.h): v o i dq s o r t ( v o i d* b a s e ,s i z e _ tn m e m b ,s i z e _ ts i z e , i n t ( * c o m p a r ) ( c o n s tv o i d* ,c o n s tv o i d* ) ) ; Note the use of v oid*s to allow qsort to operate on any kind of data (in C+ + , y ou'd norm ally use tem plates for this task, but C+ + also allows the use of v oid* pointers) because v oid* pointers can point to any thing. Because we don't know the size of the indiv idual elem ents in a v oid* array , we m ust giv e qsort the num ber of elem ents, nm em b, of the array to be sorted, base, in addition to the standard requirem ent of giv ing the length, size, of the input. But what we're really interested in is the com par argum ent to qsort: it's a function pointer that takes two v oid *s and returns an int. This allows any one to specify how to sort the elem ents of the array base without hav ing to write a specialized sorting algorithm . Note, also, that com par returns an int; the function pointed to should return -1 if the first argum ent is less than the second, 0 if they are equal, or 1 if the second is less than the first. For instance, to sort an array of num bers in ascending order, we could write code like this: # i n c l u d e< s t d l i b . h > i n ti n t _ s o r t e r (c o n s tv o i d* f i r s t _ a r g ,c o n s tv o i d* s e c o n d _ a r g) { i n tf i r s t=* ( i n t * ) f i r s t _ a r g ; i n ts e c o n d=* ( i n t * ) s e c o n d _ a r g ; i f(f i r s t<s e c o n d) { r e t u r n1 ; } e l s ei f(f i r s t= =s e c o n d) { r e t u r n0 ; } e l s e { r e t u r n1 ; } } i n tm a i n ( ) { i n ta r r a y [ 1 0 ] ; i n ti ; / *f i l la r r a y* /
www.cprogramming.com/tutorial/function-pointers.html 3/5

3/29/13

Function Pointers in C and C++ - Cprogramming.com

f o r(i=0 ;i<1 0 ;+ + i) { a r r a y [i]=1 0-i ; } q s o r t (a r r a y ,1 0,s i z e o f (i n t) ,i n t _ s o r t e r) ; f o r(i=0 ;i<1 0 ;+ + i) { p r i n t f(" % d \ n ", a r r a y [i]) ; } }

Using Polymorphism and Virtual Functions Instead of Function Pointers (C++)


You can often av oid the need for explicit function pointers by using v irtual functions. For instance, y ou could write a sorting routine that takes a pointer to a class that prov ides a v irtual function called com pare: c l a s sS o r t e r { p u b l i c : v i r t u a li n tc o m p a r e( c o n s tv o i d* f i r s t ,c o n s tv o i d* s e c o n d ) ; } ; / /c p p _ q s o r t ,aq s o r tu s i n gC + +f e a t u r e sl i k ev i r t u a lf u n c t i o n s v o i dc p p _ q s o r t ( v o i d* b a s e ,s i z e _ tn m e m b ,s i z e _ ts i z e ,S o r t e r* c o m p a r ) ; inside cpp_qsort, whenev er a com parison is needed, com par-> com pare should be called. For classes that ov erride this v irtual function, the sort routine will get the new behav ior of that function. For instance: c l a s sA s c e n d S o r t e r:p u b l i cS o r t e r { v i r t u a li n tc o m p a r e( c o n s tv o i d * ,c o n s tv o i d * ) { i n tf i r s t=* ( i n t * ) f i r s t _ a r g ; i n ts e c o n d=* ( i n t * ) s e c o n d _ a r g ; i f(f i r s t<s e c o n d) { r e t u r n1 ; } e l s ei f(f i r s t= =s e c o n d) { r e t u r n0 ; } e l s e { r e t u r n1 ; } } } ; and then y ou could pass in a pointer to an instance of the AscendSorter to cpp_qsort to sort integers in ascending order.

But Are You Really Not Using Function Pointers?


Virtual functions are im plem ented behind the scenes using function pointers, so y ou really are using function
www.cprogramming.com/tutorial/function-pointers.html 4/5

3/29/13

Function Pointers in C and C++ - Cprogramming.com

pointers--it just happens that the com piler m akes the work easier for y ou. Using poly m orphism can be an appropriate strategy (for instance, it's used by Jav a), but it does lead to the ov erhead of hav ing to create an object rather than sim ply pass in a function pointer.

Function Pointers Summary


Syntax
Declaring Declare a function pointer as though y ou were declaring a function, except with a nam e like *foo instead of just foo: v o i d( * f o o ) ( i n t ) ; Init ializing You can get the address of a function sim ply by nam ing it: v o i df o o ( ) ; f u n c _ p o i n t e r=f o o ; or by prefixing the nam e of the function with an am persand: v o i df o o ( ) ; f u n c _ p o i n t e r=& f o o ; Invoking Inv oke the function pointed to just as if y ou were calling a function. f u n c _ p o i n t e r (a r g 1 ,a r g 2) ; or y ou m ay optionally dereference the function pointer before calling the function it points to: ( * f u n c _ p o i n t e r ) (a r g 1 ,a r g 2) ;

Benefits of Function Pointers


Function pointers prov ide a way of passing around instructions for how to do som ething You can write flexible functions and libraries that allow the program m er to choose behav ior by passing function pointers as argum ents This flexibility can also be achiev ed by using classes with v irtual functions I am grateful to Alex Hoffer and Thomas Carriero for their comments on a draft of this article. Relat ed art icles Lam bda functions in C+ + 1 1 , a replacem ent for function pointers What are Pointers? Functors in C+ + , a better function pointer

www.cprogramming.com/tutorial/function-pointers.html

5/5

Anda mungkin juga menyukai