Passing function pointer as argument to a function???

Discussion in 'C Programming' started by Charles Sullivan, Sep 19, 2005.

  1. The library function 'qsort' is declared thus:
    void qsort(void *base, size_t nmemb, size_t size,
    int(*compar)(const void *, const void *));

    If in my code I write:
    int cmp_fcn(...);
    int (*fcmp)() = &cmp_fcn;
    qsort(..., fcmp);

    then everything works. But if instead I code qsort as:

    qsort(..., &cmp_fcn);

    the compiler complains about incompatible pointer type.

    Can someone help me understand exactly what I'm passing to
    the qsort function in the "bad" code other than the pointer
    to a function and/or how this differs from the "good" code?

    How could the qsort statement be written directly without
    the use of an intermediary like 'fcmp' ?

    Thanks for your help.

    Regards,
    Charles Sullivan
     
    Charles Sullivan, Sep 19, 2005
    #1
    1. Advertising

  2. Charles Sullivan

    Eric Sosman Guest

    Charles Sullivan wrote On 09/19/05 11:05,:
    > The library function 'qsort' is declared thus:
    > void qsort(void *base, size_t nmemb, size_t size,
    > int(*compar)(const void *, const void *));
    >
    > If in my code I write:
    > int cmp_fcn(...);
    > int (*fcmp)() = &cmp_fcn;


    FYI: The `&' is harmless but unnecessary, both here
    and below.

    > qsort(..., fcmp);
    >
    > then everything works. But if instead I code qsort as:
    >
    > qsort(..., &cmp_fcn);
    >
    > the compiler complains about incompatible pointer type.
    >
    > Can someone help me understand exactly what I'm passing to
    > the qsort function in the "bad" code other than the pointer
    > to a function and/or how this differs from the "good" code?


    Well, let's see: The compiler says that cmp_fcn() is
    of the wrong type. Might this mean that there's something
    wrong with cmp_fcn()? It seems a possibility, doesn't it?
    However, this is all just speculation on my part, since you
    haven't (hint, hint) shown what cmp_fcn() looks like ...

    > How could the qsort statement be written directly without
    > the use of an intermediary like 'fcmp' ?


    By writing a cmp_fcn() that matches what qsort()
    requires.

    --
     
    Eric Sosman, Sep 19, 2005
    #2
    1. Advertising

  3. Charles Sullivan wrote:
    >
    > The library function 'qsort' is declared thus:
    > void qsort(void *base, size_t nmemb, size_t size,
    > int(*compar)(const void *, const void *));
    >
    > If in my code I write:
    > int cmp_fcn(...);
    > int (*fcmp)() = &cmp_fcn;
    > qsort(..., fcmp);
    >
    > then everything works. But if instead I code qsort as:
    >
    > qsort(..., &cmp_fcn);
    >
    > the compiler complains about incompatible pointer type.


    qsort is expecting a pointer to a function which returns an int and
    gets passed two const void * parameters. However, you are passing
    it a pointer to a function which returns int and gets passed a
    variable number of unknown parameters.

    > Can someone help me understand exactly what I'm passing to
    > the qsort function in the "bad" code other than the pointer
    > to a function and/or how this differs from the "good" code?


    When using the intermediate fcmp variable, you are passing it
    a function which returns int, and whose parameters are left
    unprototyped.

    > How could the qsort statement be written directly without
    > the use of an intermediary like 'fcmp' ?


    If cmp_fcn() does, in fact, take two const void * parameters, then
    say so by changing:

    int cmp_fcn(...);
    to
    int cmp_fcn(const void *,const void *);

    --
    +-------------------------+--------------------+-----------------------------+
    | Kenneth J. Brody | www.hvcomputer.com | |
    | kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
    +-------------------------+--------------------+-----------------------------+
    Don't e-mail me at: <mailto:>
     
    Kenneth Brody, Sep 19, 2005
    #3
  4. Charles Sullivan wrote:
    > The library function 'qsort' is declared thus:
    > void qsort(void *base, size_t nmemb, size_t size,
    > int(*compar)(const void *, const void *));
    >
    > If in my code I write:
    > int cmp_fcn(...);
    > int (*fcmp)() = &cmp_fcn;
    > qsort(..., fcmp);
    >
    > then everything works. But if instead I code qsort as:
    >
    > qsort(..., &cmp_fcn);
    >
    > the compiler complains about incompatible pointer type.
    >
    > Can someone help me understand exactly what I'm passing to
    > the qsort function in the "bad" code other than the pointer
    > to a function and/or how this differs from the "good" code?
    >
    > How could the qsort statement be written directly without
    > the use of an intermediary like 'fcmp' ?


    Exactly as you use fcmp. To clarify:

    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string.h>

    #define ASIZE 10

    int cmp_fcn(const void *e1, const void *e2);

    int main(void)
    {
    double asrc[ASIZE], awrk[ASIZE];
    int (*fcmp) () = cmp_fcn;
    size_t i;
    srand(time(0));
    printf(" example using cmp_fcn as argument\n");
    for (i = 0; i < ASIZE; i++)
    asrc = rand() / (1. + RAND_MAX);
    memcpy(awrk, asrc, sizeof asrc);
    qsort(awrk, ASIZE, sizeof *awrk, cmp_fcn);
    for (i = 0; i < ASIZE; i++)
    printf("%lu: %f %f\n", (unsigned long) i, asrc, awrk);
    printf("\n");

    printf(" example using fcmp as argument\n");
    for (i = 0; i < ASIZE; i++)
    asrc = rand() / (1. + RAND_MAX);
    memcpy(awrk, asrc, sizeof asrc);
    qsort(awrk, ASIZE, sizeof *awrk, fcmp);
    for (i = 0; i < ASIZE; i++)
    printf("%lu: %f %f\n", (unsigned long) i, asrc, awrk);
    return 0;
    }


    int cmp_fcn(const void *e1, const void *e2)
    {
    const double *p1 = e1, *p2 = e2;
    return (*p1 > *p2) ? 1 : (*p1 < *p2) ? -1 : 0;
    }

    example using cmp_fcn as argument
    0: 0.563498 0.111813
    1: 0.195851 0.195851
    2: 0.111813 0.254336
    3: 0.294201 0.294201
    4: 0.318893 0.318893
    5: 0.586812 0.511567
    6: 0.724280 0.563498
    7: 0.925669 0.586812
    8: 0.511567 0.724280
    9: 0.254336 0.925669

    example using fcmp as argument
    0: 0.887919 0.053615
    1: 0.053615 0.134536
    2: 0.471209 0.211441
    3: 0.457827 0.240006
    4: 0.640444 0.457827
    5: 0.211441 0.471209
    6: 0.240006 0.511690
    7: 0.511690 0.640444
    8: 0.699548 0.699548
    9: 0.134536 0.887919
     
    Martin Ambuhl, Sep 19, 2005
    #4
  5. Kenneth Brody <> writes:
    > Charles Sullivan wrote:
    >>
    >> The library function 'qsort' is declared thus:
    >> void qsort(void *base, size_t nmemb, size_t size,
    >> int(*compar)(const void *, const void *));
    >>
    >> If in my code I write:
    >> int cmp_fcn(...);
    >> int (*fcmp)() = &cmp_fcn;
    >> qsort(..., fcmp);
    >>
    >> then everything works. But if instead I code qsort as:
    >>
    >> qsort(..., &cmp_fcn);
    >>
    >> the compiler complains about incompatible pointer type.

    >
    > qsort is expecting a pointer to a function which returns an int and
    > gets passed two const void * parameters. However, you are passing
    > it a pointer to a function which returns int and gets passed a
    > variable number of unknown parameters.


    No, he's not. A function that takes a variable number of arguments
    must have at least one named argument before the "...". Note also his
    use of "..." in the call to qsort. The ellipsis isn't being used as C
    syntax; it's just an ellipsis.

    He's just not showing us exactly what he's doing -- which means we
    can't guess what the problem is.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Sep 19, 2005
    #5
  6. Charles Sullivan wrote on 19/09/05 :
    > The library function 'qsort' is declared thus:
    > void qsort(void *base, size_t nmemb, size_t size,
    > int(*compar)(const void *, const void *));
    >
    > If in my code I write:
    > int cmp_fcn(...);
    > int (*fcmp)() = &cmp_fcn;


    You don't need the &.

    > qsort(..., fcmp);
    >
    > then everything works. But if instead I code qsort as:
    >
    > qsort(..., &cmp_fcn);


    You don't need the &.

    qsort(..., cmp_fcn);

    > the compiler complains about incompatible pointer type.


    How exactly is cmp_fcn() prototyped ?

    > Can someone help me understand exactly what I'm passing to
    > the qsort function in the "bad" code other than the pointer
    > to a function and/or how this differs from the "good" code?


    The compare function must exactly have this prototype :

    int compare_function (void const *, void const *);

    > How could the qsort statement be written directly without
    > the use of an intermediary like 'fcmp' ?


    Using the correct prototype for the compare function. We all do that
    every day... (well, sort of)

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    I once asked an expert COBOL programmer, how to
    declare local variables in COBOL, the reply was:
    "what is a local variable?"
     
    Emmanuel Delahaye, Sep 19, 2005
    #6
  7. On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:

    > Kenneth Brody <> writes:
    >> Charles Sullivan wrote:
    >>>
    >>> The library function 'qsort' is declared thus:
    >>> void qsort(void *base, size_t nmemb, size_t size,
    >>> int(*compar)(const void *, const void *));
    >>>
    >>> If in my code I write:
    >>> int cmp_fcn(...);
    >>> int (*fcmp)() = &cmp_fcn;
    >>> qsort(..., fcmp);
    >>>
    >>> then everything works. But if instead I code qsort as:
    >>>
    >>> qsort(..., &cmp_fcn);
    >>>
    >>> the compiler complains about incompatible pointer type.

    >>
    >> qsort is expecting a pointer to a function which returns an int and
    >> gets passed two const void * parameters. However, you are passing
    >> it a pointer to a function which returns int and gets passed a
    >> variable number of unknown parameters.

    >
    > No, he's not. A function that takes a variable number of arguments
    > must have at least one named argument before the "...". Note also his
    > use of "..." in the call to qsort. The ellipsis isn't being used as C
    > syntax; it's just an ellipsis.
    >
    > He's just not showing us exactly what he's doing -- which means we
    > can't guess what the problem is.


    Mea culpa. I had forgotten about the C syntax and used "..." to
    represent stuff I _thought_ irrelevant to the question.

    Here's an example which illustrates the way I've been using
    qsort:
    -------------------------------------
    #include <stdio.h>
    #include <stdlib.h>

    int val[] = { 3, 2, 1, 4, 5 };

    int cmp_fcn ( int *one, int *two )
    {
    return (*one < *two) ? -1 :
    (*one > *two) ? 1 : 0;
    }

    int main ( void )
    {
    int (*fcmp)() = &cmp_fcn;
    qsort((void *)val, 5, sizeof(int), fcmp);
    printf("%d %d %d %d %d\n",
    val[0], val[1], val[2], val[3], val[4]);
    return 0;
    }
    -----------------------------------

    Regards,
    Charles Sullivan
     
    Charles Sullivan, Sep 20, 2005
    #7
  8. On Mon, 19 Sep 2005 23:36:43 GMT, Charles Sullivan
    <> wrote:

    >On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
    >
    >> Kenneth Brody <> writes:
    >>> Charles Sullivan wrote:
    >>>>
    >>>> The library function 'qsort' is declared thus:
    >>>> void qsort(void *base, size_t nmemb, size_t size,
    >>>> int(*compar)(const void *, const void *));
    >>>>
    >>>> If in my code I write:
    >>>> int cmp_fcn(...);
    >>>> int (*fcmp)() = &cmp_fcn;
    >>>> qsort(..., fcmp);
    >>>>
    >>>> then everything works. But if instead I code qsort as:
    >>>>
    >>>> qsort(..., &cmp_fcn);
    >>>>
    >>>> the compiler complains about incompatible pointer type.
    >>>
    >>> qsort is expecting a pointer to a function which returns an int and
    >>> gets passed two const void * parameters. However, you are passing
    >>> it a pointer to a function which returns int and gets passed a
    >>> variable number of unknown parameters.

    >>
    >> No, he's not. A function that takes a variable number of arguments
    >> must have at least one named argument before the "...". Note also his
    >> use of "..." in the call to qsort. The ellipsis isn't being used as C
    >> syntax; it's just an ellipsis.
    >>
    >> He's just not showing us exactly what he's doing -- which means we
    >> can't guess what the problem is.

    >
    >Mea culpa. I had forgotten about the C syntax and used "..." to
    >represent stuff I _thought_ irrelevant to the question.
    >
    >Here's an example which illustrates the way I've been using
    >qsort:
    >-------------------------------------
    >#include <stdio.h>
    >#include <stdlib.h>
    >
    >int val[] = { 3, 2, 1, 4, 5 };
    >
    >int cmp_fcn ( int *one, int *two )


    cmp_fcn has the wrong type for a function whose address is to be
    passed to qsort. The two parameters need to be const void *.

    >{
    > return (*one < *two) ? -1 :
    > (*one > *two) ? 1 : 0;
    >}
    >
    >int main ( void )
    >{
    > int (*fcmp)() = &cmp_fcn;


    fcmp has the wrong type for a pointer to be used as an argument to
    qsort. fcmp is a pointer to function (returning int) about whose
    arguments (type and quantity) absolutely nothing is known. qsort
    needs a pointer to function returning int about whose arguments
    everything is known.

    > qsort((void *)val, 5, sizeof(int), fcmp);
    > printf("%d %d %d %d %d\n",
    > val[0], val[1], val[2], val[3], val[4]);
    > return 0;
    >}


    Try increasing the warning level on your compiler.


    <<Remove the del for email>>
     
    Barry Schwarz, Sep 20, 2005
    #8
  9. Charles Sullivan <> writes:
    > On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
    >> Kenneth Brody <> writes:
    >>> Charles Sullivan wrote:
    >>>> The library function 'qsort' is declared thus:
    >>>> void qsort(void *base, size_t nmemb, size_t size,
    >>>> int(*compar)(const void *, const void *));
    >>>>
    >>>> If in my code I write:
    >>>> int cmp_fcn(...);
    >>>> int (*fcmp)() = &cmp_fcn;
    >>>> qsort(..., fcmp);
    >>>>
    >>>> then everything works. But if instead I code qsort as:
    >>>>
    >>>> qsort(..., &cmp_fcn);
    >>>>
    >>>> the compiler complains about incompatible pointer type.
    >>>
    >>> qsort is expecting a pointer to a function which returns an int and
    >>> gets passed two const void * parameters. However, you are passing
    >>> it a pointer to a function which returns int and gets passed a
    >>> variable number of unknown parameters.

    >>
    >> No, he's not. A function that takes a variable number of arguments
    >> must have at least one named argument before the "...". Note also his
    >> use of "..." in the call to qsort. The ellipsis isn't being used as C
    >> syntax; it's just an ellipsis.
    >>
    >> He's just not showing us exactly what he's doing -- which means we
    >> can't guess what the problem is.

    >
    > Mea culpa. I had forgotten about the C syntax and used "..." to
    > represent stuff I _thought_ irrelevant to the question.
    >
    > Here's an example which illustrates the way I've been using
    > qsort:
    > -------------------------------------
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int val[] = { 3, 2, 1, 4, 5 };
    >
    > int cmp_fcn ( int *one, int *two )
    > {
    > return (*one < *two) ? -1 :
    > (*one > *two) ? 1 : 0;
    > }
    >
    > int main ( void )
    > {
    > int (*fcmp)() = &cmp_fcn;
    > qsort((void *)val, 5, sizeof(int), fcmp);
    > printf("%d %d %d %d %d\n",
    > val[0], val[1], val[2], val[3], val[4]);
    > return 0;
    > }
    > -----------------------------------


    Yup, the stuff you deleted was exactly what's relevant to the problem.

    The "compar" argument to qsort must be a pointer to a function taking
    two arguments of type "const void *" and returning a result of type
    int. You're providing a pointer to a function taking two arguments of
    type int* and returning a result of type int. The types are
    incompatible.

    You need to declare your cmp_fcn() function as:

    int cmp_fcn(const void *one, const void *2);

    Here's a modified version of your program:

    #include <stdio.h>
    #include <stdlib.h>

    int val[] = { 3, 2, 1, 4, 5 };

    int cmp_fcn ( const void *one, const void *two )
    {
    return (*(int*)one < *(int*)two) ? -1 :
    (*(int*)one > *(int*)two) ? 1 : 0;
    }

    int main ( void )
    {
    qsort(val,
    sizeof val / sizeof val[0],
    sizeof val[0],
    cmp_fcn);
    printf("%d %d %d %d %d\n",
    val[0], val[1], val[2], val[3], val[4]);
    return 0;
    }

    Note that I've changed all four arguments to qsort().

    For the first argument, I dropped the cast to void*. As long as
    qsort's prototype is visible (which it is, since you have the
    "#include <stdlib.h>", the conversion is done implicitly.

    For the second argument, I compute the size of the val array rather
    than assuming it's 5. This lets you change the size without having
    to modify the call.

    Similarly, the third argument is "sizeof val[0]" rather than
    "sizeof(int)", allowing you to change the type of the array without
    changing the qsort call (though you would have to change the
    cmp_fcn function).

    Finally, I pass the name of the function directly to qsort() rather
    than storing it in a variable. The name of a function is implicitly
    converted to a pointer-to-function in most contexts. (The exceptions
    are the argument to sizeof, which makes "sizeof func" illegal rather
    than yielding the size of a function pointer, and the argument to a
    unary "&" operator, which makes &func nearly equivalent to func.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Sep 20, 2005
    #9
  10. On Mon, 19 Sep 2005 17:44:30 -0700, Barry Schwarz wrote:

    > On Mon, 19 Sep 2005 23:36:43 GMT, Charles Sullivan
    > <> wrote:
    >
    >>On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
    >>
    >>> Kenneth Brody <> writes:
    >>>> Charles Sullivan wrote:
    >>>>>
    >>>>> The library function 'qsort' is declared thus:
    >>>>> void qsort(void *base, size_t nmemb, size_t size,
    >>>>> int(*compar)(const void *, const void *));
    >>>>>
    >>>>> If in my code I write:
    >>>>> int cmp_fcn(...);
    >>>>> int (*fcmp)() = &cmp_fcn;
    >>>>> qsort(..., fcmp);
    >>>>>
    >>>>> then everything works. But if instead I code qsort as:
    >>>>>
    >>>>> qsort(..., &cmp_fcn);
    >>>>>
    >>>>> the compiler complains about incompatible pointer type.
    >>>>
    >>>> qsort is expecting a pointer to a function which returns an int and
    >>>> gets passed two const void * parameters. However, you are passing
    >>>> it a pointer to a function which returns int and gets passed a
    >>>> variable number of unknown parameters.
    >>>
    >>> No, he's not. A function that takes a variable number of arguments
    >>> must have at least one named argument before the "...". Note also his
    >>> use of "..." in the call to qsort. The ellipsis isn't being used as C
    >>> syntax; it's just an ellipsis.
    >>>
    >>> He's just not showing us exactly what he's doing -- which means we
    >>> can't guess what the problem is.

    >>
    >>Mea culpa. I had forgotten about the C syntax and used "..." to
    >>represent stuff I _thought_ irrelevant to the question.
    >>
    >>Here's an example which illustrates the way I've been using
    >>qsort:
    >>-------------------------------------
    >>#include <stdio.h>
    >>#include <stdlib.h>
    >>
    >>int val[] = { 3, 2, 1, 4, 5 };
    >>
    >>int cmp_fcn ( int *one, int *two )

    >
    > cmp_fcn has the wrong type for a function whose address is to be
    > passed to qsort. The two parameters need to be const void *.
    >
    >>{
    >> return (*one < *two) ? -1 :
    >> (*one > *two) ? 1 : 0;
    >>}
    >>
    >>int main ( void )
    >>{
    >> int (*fcmp)() = &cmp_fcn;

    >
    > fcmp has the wrong type for a pointer to be used as an argument to
    > qsort. fcmp is a pointer to function (returning int) about whose
    > arguments (type and quantity) absolutely nothing is known. qsort
    > needs a pointer to function returning int about whose arguments
    > everything is known.
    >
    >> qsort((void *)val, 5, sizeof(int), fcmp);
    >> printf("%d %d %d %d %d\n",
    >> val[0], val[1], val[2], val[3], val[4]);
    >> return 0;
    >>}

    >
    > Try increasing the warning level on your compiler.
    >


    OK, if I change the function as suggested by you all to:
    --------------------
    int cmp_fcn ( const void *x1, const void *x2 )
    {
    const int *one = x1; const int *two = x2;
    return (*one < *two) ? -1 :
    (*one > *two) ? 1 : 0;
    }
    --------------------
    then it works both ways. (Thanks guys.)

    But I've yet to find a (gcc-3.2.2-5) compiler warning level that
    grunts even a little with my original (working) code. As far as
    I can remember I've used that syntax on a variety of Unix-like
    systems over the years and never got a warning about it.

    Thanks for all your help.

    Regards,
    Charles Sullivan
     
    Charles Sullivan, Sep 20, 2005
    #10
  11. On Tue, 20 Sep 2005 00:46:40 +0000, Keith Thompson wrote:

    > Charles Sullivan <> writes:
    >> On Mon, 19 Sep 2005 20:12:17 +0000, Keith Thompson wrote:
    >>> Kenneth Brody <> writes:
    >>>> Charles Sullivan wrote:
    >>>>> The library function 'qsort' is declared thus:
    >>>>> void qsort(void *base, size_t nmemb, size_t size,
    >>>>> int(*compar)(const void *, const void *));
    >>>>>
    >>>>> If in my code I write:
    >>>>> int cmp_fcn(...);
    >>>>> int (*fcmp)() = &cmp_fcn;
    >>>>> qsort(..., fcmp);
    >>>>>
    >>>>> then everything works. But if instead I code qsort as:
    >>>>>
    >>>>> qsort(..., &cmp_fcn);
    >>>>>
    >>>>> the compiler complains about incompatible pointer type.
    >>>>
    >>>> qsort is expecting a pointer to a function which returns an int and
    >>>> gets passed two const void * parameters. However, you are passing
    >>>> it a pointer to a function which returns int and gets passed a
    >>>> variable number of unknown parameters.
    >>>
    >>> No, he's not. A function that takes a variable number of arguments
    >>> must have at least one named argument before the "...". Note also his
    >>> use of "..." in the call to qsort. The ellipsis isn't being used as C
    >>> syntax; it's just an ellipsis.
    >>>
    >>> He's just not showing us exactly what he's doing -- which means we
    >>> can't guess what the problem is.

    >>
    >> Mea culpa. I had forgotten about the C syntax and used "..." to
    >> represent stuff I _thought_ irrelevant to the question.
    >>
    >> Here's an example which illustrates the way I've been using
    >> qsort:
    >> -------------------------------------
    >> #include <stdio.h>
    >> #include <stdlib.h>
    >>
    >> int val[] = { 3, 2, 1, 4, 5 };
    >>
    >> int cmp_fcn ( int *one, int *two )
    >> {
    >> return (*one < *two) ? -1 :
    >> (*one > *two) ? 1 : 0;
    >> }
    >>
    >> int main ( void )
    >> {
    >> int (*fcmp)() = &cmp_fcn;
    >> qsort((void *)val, 5, sizeof(int), fcmp);
    >> printf("%d %d %d %d %d\n",
    >> val[0], val[1], val[2], val[3], val[4]);
    >> return 0;
    >> }
    >> -----------------------------------

    >
    > Yup, the stuff you deleted was exactly what's relevant to the problem.
    >
    > The "compar" argument to qsort must be a pointer to a function taking
    > two arguments of type "const void *" and returning a result of type
    > int. You're providing a pointer to a function taking two arguments of
    > type int* and returning a result of type int. The types are
    > incompatible.
    >
    > You need to declare your cmp_fcn() function as:
    >
    > int cmp_fcn(const void *one, const void *2);
    >
    > Here's a modified version of your program:
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int val[] = { 3, 2, 1, 4, 5 };
    >
    > int cmp_fcn ( const void *one, const void *two )
    > {
    > return (*(int*)one < *(int*)two) ? -1 :
    > (*(int*)one > *(int*)two) ? 1 : 0;
    > }
    >
    > int main ( void )
    > {
    > qsort(val,
    > sizeof val / sizeof val[0],
    > sizeof val[0],
    > cmp_fcn);
    > printf("%d %d %d %d %d\n",
    > val[0], val[1], val[2], val[3], val[4]);
    > return 0;
    > }
    >
    > Note that I've changed all four arguments to qsort().
    >
    > For the first argument, I dropped the cast to void*. As long as
    > qsort's prototype is visible (which it is, since you have the
    > "#include <stdlib.h>", the conversion is done implicitly.
    >
    > For the second argument, I compute the size of the val array rather
    > than assuming it's 5. This lets you change the size without having
    > to modify the call.
    >
    > Similarly, the third argument is "sizeof val[0]" rather than
    > "sizeof(int)", allowing you to change the type of the array without
    > changing the qsort call (though you would have to change the
    > cmp_fcn function).
    >
    > Finally, I pass the name of the function directly to qsort() rather
    > than storing it in a variable. The name of a function is implicitly
    > converted to a pointer-to-function in most contexts. (The exceptions
    > are the argument to sizeof, which makes "sizeof func" illegal rather
    > than yielding the size of a function pointer, and the argument to a
    > unary "&" operator, which makes &func nearly equivalent to func.)


    Thanks Keith. I usually do what you've suggested in my actual
    code, except for argument 3 (too easy to forget to change the
    cmp-fcn function and start getting weird errors). And my
    inability to follow your suggestion for argument 4 is what
    prompted my original query.

    Regards,
    Charles Sullivan
     
    Charles Sullivan, Sep 20, 2005
    #11
  12. Charles Sullivan wrote:
    > int cmp_fcn ( int *one, int *two )


    This is incorrect. The prototype for qsort demands that the
    comparison function be of type
    int cmp_fcn(const void *e1, const void *e2);

    See my post
    Message-ID: <PTCXe.690$>
    Date: Mon, 19 Sep 2005 17:50:39 GMT

    for the correct way of doing this.
     
    Martin Ambuhl, Sep 20, 2005
    #12
  13. Charles Sullivan wrote on 20/09/05 :
    > Here's an example which illustrates the way I've been using
    > qsort:
    > -------------------------------------
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int val[] = { 3, 2, 1, 4, 5 };
    >
    > int cmp_fcn ( int *one, int *two )


    Wrong prototype.

    > {
    > return (*one < *two) ? -1 :
    > (*one > *two) ? 1 : 0;


    Complicated. A simple difference is enough. The 3 domains are <0, 0, >0

    > }
    >
    > int main ( void )
    > {
    > int (*fcmp)() = &cmp_fcn;


    Useless pointer to function masking the parameters error.

    > qsort((void *)val, 5, sizeof(int), fcmp);


    USeless cast. Now, I have a 18 values array of doubles. What do I do ?

    > printf("%d %d %d %d %d\n",
    > val[0], val[1], val[2], val[3], val[4]);


    Now, I have a 18 values array of ints. What do I do ?

    > return 0;
    > }
    > -----------------------------------


    stay stright, simple and conforming:

    #include <stdio.h>
    #include <stdlib.h>

    #define NELEM(a) (sizeof (a) / sizeof *(a))

    static int cmp_fcn (void const *one, void const *two)
    {
    int const *p_one = one;
    int const *p_two = two;

    return *p_one - *p_two;
    }

    static void print (int const *a, size_t n)
    {
    size_t i;
    for (i = 0; i < n; i++)
    {
    printf ("%d ", a);
    }
    printf ("\n");
    }

    int main (void)
    {
    int val[] =
    {3, 2, 5, 1, 4};

    print (val, NELEM (val));
    qsort (val, NELEM (val), sizeof *val, cmp_fcn);
    print (val, NELEM (val));

    return 0;
    }

    --
    Emmanuel
    The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
    The C-library: http://www.dinkumware.com/refxc.html

    "Clearly your code does not meet the original spec."
    "You are sentenced to 30 lashes with a wet noodle."
    -- Jerry Coffin in a.l.c.c++
     
    Emmanuel Delahaye, Sep 20, 2005
    #13
  14. "Emmanuel Delahaye" <> writes:
    > Charles Sullivan wrote on 20/09/05 :

    [...]
    >> int cmp_fcn ( int *one, int *two )

    >
    > Wrong prototype.


    Yes.

    >> {
    >> return (*one < *two) ? -1 :
    >> (*one > *two) ? 1 : 0;

    >
    > Complicated. A simple difference is enough. The 3 domains are <0, 0, >0


    No. Subtraction invokes undefined behavior on overflow.

    > stay stright, simple and conforming:
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > #define NELEM(a) (sizeof (a) / sizeof *(a))
    >
    > static int cmp_fcn (void const *one, void const *two)
    > {
    > int const *p_one = one;
    > int const *p_two = two;
    >
    > return *p_one - *p_two;
    > }
    >
    > static void print (int const *a, size_t n)
    > {
    > size_t i;
    > for (i = 0; i < n; i++)
    > {
    > printf ("%d ", a);
    > }
    > printf ("\n");
    > }
    >
    > int main (void)
    > {
    > int val[] =
    > {3, 2, 5, 1, 4};
    >
    > print (val, NELEM (val));
    > qsort (val, NELEM (val), sizeof *val, cmp_fcn);
    > print (val, NELEM (val));
    >
    > return 0;
    > }


    Try changing the initial value of val to

    {3, 2, 5, 1, 4, INT_MAX, INT_MIN}

    (with "#include <limits.h", of course).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Sep 20, 2005
    #14
  15. On Tue, 20 Sep 2005 19:40:21 +0000, Keith Thompson wrote:

    > "Emmanuel Delahaye" <> writes:
    >> Charles Sullivan wrote on 20/09/05 :

    > [...]
    >>> int cmp_fcn ( int *one, int *two )

    >>
    >> Wrong prototype.

    >
    > Yes.
    >
    >>> {
    >>> return (*one < *two) ? -1 :
    >>> (*one > *two) ? 1 : 0;

    >>
    >> Complicated. A simple difference is enough. The 3 domains are <0, 0, >0

    >
    > No. Subtraction invokes undefined behavior on overflow.
    >
    >> stay stright, simple and conforming:
    >>
    >> #include <stdio.h>
    >> #include <stdlib.h>
    >>
    >> #define NELEM(a) (sizeof (a) / sizeof *(a))
    >>
    >> static int cmp_fcn (void const *one, void const *two)
    >> {
    >> int const *p_one = one;
    >> int const *p_two = two;
    >>
    >> return *p_one - *p_two;
    >> }
    >>
    >> static void print (int const *a, size_t n)
    >> {
    >> size_t i;
    >> for (i = 0; i < n; i++)
    >> {
    >> printf ("%d ", a);
    >> }
    >> printf ("\n");
    >> }
    >>
    >> int main (void)
    >> {
    >> int val[] =
    >> {3, 2, 5, 1, 4};
    >>
    >> print (val, NELEM (val));
    >> qsort (val, NELEM (val), sizeof *val, cmp_fcn);
    >> print (val, NELEM (val));
    >>
    >> return 0;
    >> }

    >
    > Try changing the initial value of val to
    >
    > {3, 2, 5, 1, 4, INT_MAX, INT_MIN}
    >
    > (with "#include <limits.h", of course).


    No need to nitpick the inner details - the code I posted was meant
    only to illustrate the problem as simply as possible. (My first
    attempt (with the "...") turned out to mask the real problem.)

    Regards,
    Charles Sullivan
     
    Charles Sullivan, Sep 20, 2005
    #15
  16. On Tue, 20 Sep 2005 06:26:45 +0000, Martin Ambuhl wrote:

    > Charles Sullivan wrote:
    >> int cmp_fcn ( int *one, int *two )

    >
    > This is incorrect. The prototype for qsort demands that the
    > comparison function be of type
    > int cmp_fcn(const void *e1, const void *e2);
    >
    > See my post
    > Message-ID: <PTCXe.690$>
    > Date: Mon, 19 Sep 2005 17:50:39 GMT
    >
    > for the correct way of doing this.


    Yes, I followed your example and resolved the problem. Many thanks
    for taking the time to respond and to generate the example.

    Regards,
    Charles Sullivan
     
    Charles Sullivan, Sep 20, 2005
    #16
  17. Charles Sullivan <> writes:
    > On Tue, 20 Sep 2005 19:40:21 +0000, Keith Thompson wrote:
    >> "Emmanuel Delahaye" <> writes:
    >>> Charles Sullivan wrote on 20/09/05 :

    >> [...]
    >>>> int cmp_fcn ( int *one, int *two )
    >>>
    >>> Wrong prototype.

    >>
    >> Yes.
    >>
    >>>> {
    >>>> return (*one < *two) ? -1 :
    >>>> (*one > *two) ? 1 : 0;
    >>>
    >>> Complicated. A simple difference is enough. The 3 domains are <0, 0, >0

    >>
    >> No. Subtraction invokes undefined behavior on overflow.

    [...]
    > No need to nitpick the inner details - the code I posted was meant
    > only to illustrate the problem as simply as possible. (My first
    > attempt (with the "...") turned out to mask the real problem.)


    The nitpick was directed at what Emmanuel Delahaye posted, not at you
    (and neither of you should take it personally). Questions here often
    spawn lengthy discussion, sometimes raising points that have little to
    do with the original question.

    We comp.lang.c regulars are pathologically incapable of leaving an
    error uncorrected. This is, IMHO, a good thing.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Sep 21, 2005
    #17
  18. Emmanuel Delahaye, Sep 21, 2005
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. glen stark
    Replies:
    3
    Views:
    542
    glen stark
    Sep 30, 2003
  2. jimjim
    Replies:
    16
    Views:
    873
    Jordan Abel
    Mar 28, 2006
  3. Vijai Kalyan
    Replies:
    4
    Views:
    745
    Vijai Kalyan
    Nov 8, 2005
  4. Trans
    Replies:
    3
    Views:
    210
    Robert Klemme
    Jan 26, 2005
  5. User1014
    Replies:
    1
    Views:
    201
    Richard Cornford
    Nov 30, 2006
Loading...

Share This Page