Pointer to Function

Im working on an example utilizing pointers to functions.

In the code, first they declare a function:

1
2
void qsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *));


What the above says is that qsort is a function that returns void and accepts four parameters/arguments:
1) A void pointer array
2) an integer
3) another integer
4) a function. When you pass, say, function 1 to function 2 you are essentially passing function 1's address and so in the arguments of function 2, you must have a pointer to function 1.Is this making sense?

Now in this same example, later in the code, the caller function looks like this:

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


Im sure you can see my problem already. The caller function qsort does not seem to have the same layout as its declaration. Ignore argument 1,2 and 3 and look at 4. The fourth parameter says its passing a "nameless" function because all it says is: "(*)"?? Shouldnt there be a name there? Something like:
(*function1). Plus why the heck is there an additional attachment of:
(numeric ? numcmp : strcmp)? It makes me think that these two sides of the problem arise from the same coin. Maybe it should be something like:
(int (*(numeric ? numcmp : strcmp))(void*,void))?

BTW, its taken from Ritchie and Kernighan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <string.h>
#define MAXLINES 5000 /* max #lines to be sorted */
char *lineptr[MAXLINES]; /* pointers to text lines */
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *));
int numcmp(char *, char *);
/* sort input lines */
main(int argc, char *argv[])
{
  int nlines; /* number of input lines read */
  int numeric = 0; /* 1 if numeric sort */
  if (argc > 1 && strcmp(argv[1], "-n") == 0)
    numeric = 1;
  if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
     qsort((void**) lineptr, 0, nlines-1,
      (int (*)(void*,void*))(numeric ? numcmp : strcmp));
     writelines(lineptr, nlines);
     return 0;
} else {
     printf("input too big to sort\n");
     return 1;
}
}
Last edited on
think of that line as a cast
The numeric ? numcmp : strcmp statement is boolean, there really isn't a reason to cast it to an int like you are thinking.

Why are we still stuck using void pointers to cast only to have to recast latter? Outside of the Win32 API only old people do this. Take a look here: http://www.cplusplus.com/doc/tutorial/templates/ trust me it will make things like this a whole lot easier.
The point im making is surely that boolean expression should be within that first bracket and not appended at the end?

Somehting like
int (*numeric ? numcmp : strcmp)(void*,void*)

EDIT: nevermind that isnt right. You only need pass the function name.

numcmp and strcmp are both functions and so their names should be to the right of the asterisk designator instead of simply having (*) and adding the boolean at the end, which doesnt make sense.
This really looks like an error. I havent tried compiling yet, though.
Last edited on
Okay I tried compiling and it gives me an error on line 9:
conflicting types for 'qsort'


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINES 5000 /* max #lines to be sorted */
char *lineptr[MAXLINES]; /* pointers to text lines */
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *));
int numcmp(char *, char *);
/* sort input lines */

/* numcmp: compare s1 and s2 numerically */
int numcmp(char *s1, char *s2)
{
double v1, v2;
v1 = atof(s1);
v2 = atof(s2);
if (v1 < v2)
return -1;
else if (v1 > v2)
return 1;
else
return 0;
}

void swap(void *v[], int i, int j;)
{
void *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}

/* qsort: sort v[left]...v[right] into increasing order */
void qsort(void *v[], int left, int right,
int (*comp)(void *, void *))
{
int i, last;
void swap(void *v[], int, int);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if ((*comp)(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1, comp);
qsort(v, last+1, right, comp);
}

main(int argc, char *argv[])
{
int nlines; /* number of input lines read */
int numeric = 0; /* 1 if numeric sort */
if (argc > 1 && strcmp(argv[1], "-n") == 0)
numeric = 1;
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
qsort((void**) lineptr, 0, nlines-1,
(int (*)(void*,void*))(numeric ? numcmp : strcmp));
writelines(lineptr, nlines);
107
return 0;
} else {
printf("input too big to sort\n");
return 1;
}
}
Last edited on
kfmfe04 wrote:
think of that line as a cast


Hmmm, Im only thinking of what youre saying now.

You mean

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

that entire part in bold is a cast? So if we never cast it, it would simply be:

numeric ? numcmp : strcmp

?
Last edited on
Okay so basically in this thread im trying to understand what the below small piece of code means:

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

I cant believe Kernighan and Ritchie just throws me in the deep end here. The following paragraph just mentions "notice the elaborate use of the cast". Anyway after studying it for what seems to be an hour I think it means:

the outer brackets means its a cast (to either numcmp or strcmp boolean). These numcmp and strcmp are not variables or single values but rather functions and as such to cast them involves changing their inputs and outputs. numcmp (numerical compare) takes input of integers while strcmp (string compare) takes input of characters. Thats why to deal with them both (depending on the boolean) using one function, we cast their inputs to void:

(void*,void*)

they will both return int values so that remains int.
Thus, only thing left bugging me is that darn asterisk between parenthesis which resembles a titty:
(*)

Any literature explaining casts better? Kernighan doesnt do a good job while the tutorial on this site never mentions such complicated statements.
right (bold is the cast), but still invalid - the compiler will not allow the cast

you need to do the casting inside the comparison function: Lines 38, 42

apologies for using C++ templates - didn't want to copy-paste code (which you can do, if you want pure C)

Original : 1 3 6 5 8 7 9 6 2 0 
Sorted   : 0 1 2 3 5 6 6 7 8 9 
Original : 1 3 6 5 8 7 9 6 2 0 
Sorted   : 0 1 2 3 5 6 6 7 8 9 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdlib.h>
#include <stdio.h>

template<typename T>
void mysorter( T* arr, const char* fmt, int n, int (*sortfn)(const void*,const void*) )
{
  unsigned i;

  printf("Original : ");
  for(i=0; i<n; i++)
    printf( fmt, arr[i] );
  printf( "\n" );

  qsort( arr, n, sizeof(T), sortfn );

  printf("Sorted   : ");
  for(i=0; i<n; i++)
    printf( fmt, arr[i] );
  printf( "\n" );
}

static void populate( int* num, char** str, int n )
{
  for ( int i=0; i<n; ++i ) {
    str[i]  = (char *) calloc( 2, sizeof( char ));
    *str[i] = num[i] + '0';
  }
}

static void release( char** str, int n )
{
  for ( int i=0; i<n; ++i )
    free( str[i] );
}

int numcomp(const void *i, const void *j)
{
  return *(int *)i - *(int *)j;
}
int strcomp(const void *i, const void *j)
{
  return atoi(*(char **)i) - atoi(*(char **)j);
}

int main(void)
{
  int   num[10]  = { 1, 3, 6, 5, 8, 7, 9, 6, 2, 0 };
  char *str[10];

  populate( num, str, 10 );
	
  mysorter( num, "%d ", 10, numcomp );
  mysorter( str, "%s ", 10, strcomp );

  release( str, 10 );
  return 0;
}
Last edited on
Topic archived. No new replies allowed.