# Thread: Pointer to Function

1. ## Pointer to Function

Hi all. Firstly, im new here and I hope during my stay I will help many people an in turn receive help from others. Ive been studying C programming for over a year now and have been reading through the K&R bible.

Anyway enough of that...

What I cant seem to understand is one of their examples. I wont post entire code but rather point out the essentials. Two functions are declared that both have the same data type arguments and same return type:

Code:
`int numcmp(char *, char *);`
Code:
`int strcmp(char *s, char *t)`
Thus, we can use a function pointer to point to either one of them. (Because one of the main requirements of function pointers is that they point to the same function type in both return and arguments.

Next, a function called qsort is used. It takes four arguments. Ignore the first three and focus on the fourth. It says that it takes in a function pointer whos local name is "comp". Its a function pointer because the name and * in front of it are together parenthesized. Further, this function pointer is one that points to a function that returns an int and expects two void arguments:

Code:
```void qsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *));```
Now when this function want to be called, its coded as:

Code:
```qsort((void**) lineptr, 0, nlines-1,
(int (*)(void*,void*))(numeric ? numcmp : strcmp));```
Now my problem is ultimately the fourth parameter. I simply do not get it. I understand the
Code:
`(numeric ? numcmp : strcmp)`
part. It chooses which function to call numcmp or strcmp based on a variable called numeric. But its what is infront of it that I cannot understand and the entire internet has not given me an answer:
Code:
`(int (*)(void*,void*))`
Is that some sort of cast? Why does it even need to be cast?

Why void arguments? It doesnt match the the char arguments
Why the (*)? I dont even know where to begin

2. Frankly, I think that's an ugly example, and I rarely, if ever, see function pointer casts in code.

Originally Posted by Vespasian
Is that some sort of cast? Why does it even need to be cast?
Yes, it's a cast. You need it because if you look at the comp function in qsort, it returns an int, but takes two pointers to void (not two pointers to char like strcmp and numcmp). Casts are often a way to shut up the compiler when it warns you about type mismatch. That means you think you're smarter than the compiler, which is probably not true.

Why void arguments? It doesnt match the the char arguments
The void * arguments are there because you don't want to restrict what qsort can take. Any pointer can be converted to a void pointer (EDIT: automatically by the compiler), and you can cast it back to the type you need in the comparison function. If you had char * instead of void *, every function would have to take char * (like numcmp does), and you would have to explicitly cast the params every time you call it, even outside the context of qsort.

Why the (*)? I dont even know where to begin
Just like when you cast something to int, you don't need to put a variable name in the cast part:
Code:
`int foo = (int) bar;  // notice no name inside the casting parentheses`
with a function pointer cast, you don't need to give a name to the function pointer. You're only describing the type of the thing, which in this case is pointer to function taking two void * arguments and returning an int.
Code:
`int (*)(void *, void *)`
As a note, when I do this sort of stuff, I create my own functions that take void pointers and do a cast inside to the right type:
Code:
```int string_compare(void *a, void *b)
{
return strcmp((char *) a, (char *) b);
}

int num_compare(void *a, void *b)
{
return *((int *) a) - *((int *) b);
}
...
qsort(a, b, c, string_compare);
qsort(a, b, c, num_compare);```
It may cost a slight performance hit, but it removes any ugly/difficult function pointer casts, and I generally put code readability over execution speed.

3. In other words: take out the word "comp" in your example, and that's the type (just like if you take out the word "lineptr" and you get the type void *[]).

The usual method as I understand it is to write your function properly in the first place, i.e., as taking void* arguments.

4. Originally Posted by Vespasian
What I cant seem to understand is one of their examples. I wont post entire code but rather point out the essentials. Two functions are declared that both have the same data type arguments and same return type:

Code:
`int numcmp(char *, char *);`
Code:
`int strcmp(char *s, char *t)`
Thus, we can use a function pointer to point to either one of them.
No you can't. Look closely... one is a function declaration the other is a function definition... You can point to the second one, but not the first.
(For a more detailed explaination check out "Declaration" and "Definition" in your beloved K&R)

5. Actually, yes you can.......

Originally Posted by C99
6.7.5.3.6 A parameter type list specifies the types of, and may declare identifiers for, the parameters of the function.

6. Originally Posted by AndrewHunter
Actually, yes you can.......
Not *as written*....

Also it didn't work when I tried it.

7. Thanks anduril, your explanation makes sense. But I still have questions regarding this whole "cast" business.

Originally Posted by CommonTater
Not *as written*....

Also it didn't work when I tried it.
Anyway, that was actually a typo ;-P I left out the s and the t in numcmp.

8. Originally Posted by Vespasian
Thanks anduril, your explanation makes sense. But I still have questions regarding this whole "cast" business.
What specifically don't you understand? qsort is suppose to be a generalized function, hence it deals with void* relying on the user to appropriately cast the values when it is time to use them.

9. Originally Posted by Vespasian
Now when this function want to be called, its coded as:

Code:
```qsort((void**) lineptr, 0, nlines-1,
(int (*)(void*,void*))(numeric ? numcmp : strcmp));```
Is that some sort of cast? Why does it even need to be cast?
You said you understood the bit with the fake if operator "?:" (that's not what it's called but I forget right now). Anyway, that results in a function pointer being passed to qsort as an argument; when you pass the name of a function to another function, a pointer to function type is generated. We cast the pointer to another type (EWW EWW EWW) because we want the argument to match the type of function pointer qsort uses.

10. Originally Posted by whiteflags
You said you understood the bit with the fake if operator "?:" (that's not what it's called but I forget right now).
Ternaray.

11. Originally Posted by CommonTater
Not *as written*....

Also it didn't work when I tried it.
Yes, as written. Does this not work for you?
Code:
```int numcmp(char *, char *);

int main(void) {
int (*comp)(char *, char *) = numcmp;
return 0;
}

int numcmp (char *s, char *t) {
return 5; /*Not important for this*/
}```

12. Originally Posted by tabstop
Yes, as written. Does this not work for you?
Code:
```int numcmp(char *, char *);

int main(void) {
int (*comp)(char *, char *) = numcmp;
return 0;
}

int numcmp (char *s, char *t) {
return 5; /*Not important for this*/
}```
His original example has two different names there... the second one worked, the first one did not... because it was pointing at a prototype with no function present. As in, you can't point at a prototype... you need the actual function.

13. Originally Posted by CommonTater
His original example has two different names there... the second one worked, the first one did not... because it was pointing at a prototype with no function present. As in, you can't point at a prototype... you need the actual function.
His original example has two different names there because they were two different functions. One for comparing numeric data, one for comparing string data.

14. Originally Posted by tabstop
His original example has two different names there because they were two different functions. One for comparing numeric data, one for comparing string data.
Please go back and look again... Better still...
Originally Posted by first post
int numcmp(char *, char *);
int strcmp(char *s, char *t)
See that trailing semicolon? THAT is what I was talking about...

15. The official errata page for K&R does note that this example "is not only complicated, but only barely passes muster." It doesn't really pass muster if you're being really pedantic about it, as the errata page hints at ("the example will almost certainly work in practice").

This particular example would only fail on a particularly perverse implementation, but even so, there's no particular reason to do it this way. As has been stated, create a function with the proper prototype, and you don't have to cast at all, plus you have the benefit of knowing your code is valid on all implementations, perverse or otherwise.

Popular pages Recent additions