Questions about the function pointer in K&R

Viewed 108

I'm learning C by reading K&R and got stuck in some codes from page 119 and 120. I pick up those codes that are confusing me.

char *line[MAXLINES];

Declaration:

void qsort(void *v[], int left, int right, int (*comp)(void *, void *))

caller:

qsort((void **) lineptr, 0, nlines-1, (int (*)(void*, void*))(numeric ? numcmp : strcpm));

As the declaration said, the first argument should be a array of pointer. However that's what exactly the lineptr is. So why do we need to add (void **) and what does that mean?

Another question is about the format, (int (*)(void*, void*))(numeric ? numcmp : strcpm), why is there only a single asterisk within parentheses?

Why can the (int (*)(void*, void*)) be followed by a function?

I searched on Google and try to find such format from tutorials, but I failed. So might anyone explain it? I'll really appreciate your help!!

2 Answers

"(void **)" in the caller, "(void **)lineptr", is called typecasting.
Its done to ensure that the caller is actually passing the "type" of
argument expected by the function. Here "lineptr" could be a pointer of any
type and typecasting ensures that it is passed as a "void **".

"void *[]" and "void **" can be used interchangeably, eg -
"int main(int argc, char *argv[])" or "int main(int argc, char **argv)", both are good.

About the format, (int (*)(void*, void*))(numeric ? numcmp : strcpm),
the single asterisk means that its a function pointer that you are passing
as argument which is correct since the function actually expects a function
pointer.

This part (int (*)(void*, void*)) in the statement

(int (*)(void*, void*))(numeric ? numcmp : strcpm)   

is again typecasting the result of (numeric ? numcmp : strcpm) into
the required function pointer as
per the declaration. So which ever function "numcmp" or "strcmp"
ends us being used, it will be passed to qsort as a function pointer of the
type

(int (*)(void *, void *))

(int (*)(void *, void *)) being followed by a function would mean that the
function is being typecasted as this.

Note - This is all good to understand what's happening here, but the
same can be done by having functions that match the required
signature instead of typecasting.

Q1 and Q2:

So why do we need to add (void **) and what does that mean?

A1: We need to add (void **) to assist the compiler in type conversion for multi dimensional arrays. In this case it is just to explicitly state that the conversion between incompatible pointer types is intentional and correct. Generated machine code is the same with or without this cast. We need to add (void **) because qsort is written in general way (to sort anything) and therefore accepts array of generic pointers (void *).

A2: It means to create type conversion (cast) from type 'char **' (char *lineptr[MAXLINES];) to incompatible type 'void **' (void *v[]).

Q3:

(int ()(void, void*))(numeric ? numcmp : strcpm), why is there only a single asterisk within parentheses?

A3: The (*) stands for pointer to function since 'numcmp' and 'strcpm' are pointers to functions.

Q4:

Why can the (int ()(void, void*)) be followed by a function?

A4: '(int ()(void, void*))' is type cast which is supposed to be followed by function name to convert type 'int (*)(char *, char )' to type 'int ()(void *, void *)'. It is just to explicitly state that the conversion between incompatible pointer types is intentional and correct and to have single qsort function written in general way.

K&R are cool and there is a lot of exercises in this book. Just this book is not good: 1. It teaches obsolete C constructs. 2. It teaches bad practices. 3. Many issues are not described with all details (can be okay for beginner book). 4. Some examples (at least the one that we are discussing) do not make clear point.

Related