Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   qsort (http://www.velocityreviews.com/forums/t435867-qsort.html)

 John Smith 11-17-2004 07:14 PM

qsort

I'm trying to figure out qsort(). I haven't seen any practical examples,
only synopsis. In the code below, the array is not sorted. Can someone
give me some help?

#include <stdio.h>
#include <stdlib.h>
int compare(const void* a, const void* b);

int main(void)
{
int idx;
int array[] = {243, 12, 99, 106, 122, 77, 242};

qsort(array, 7, 4, &compare);
for(idx=0; idx<7; ++idx)
printf("%d\t", array[idx]);
printf("\n");

return 0;
}

int compare(const void* a, const void* b)
{
if(a < b) return -1;
if(a == b) return 0;
if(a > b) return 1;
}

 Eric Sosman 11-17-2004 07:30 PM

Re: qsort

John Smith wrote:
> I'm trying to figure out qsort(). I haven't seen any practical examples,
> only synopsis. In the code below, the array is not sorted. Can someone
> give me some help?
>
> #include <stdio.h>
> #include <stdlib.h>
> int compare(const void* a, const void* b);
>
> int main(void)
> {
> int idx;
> int array[] = {243, 12, 99, 106, 122, 77, 242};
>
> qsort(array, 7, 4, &compare);

The `&' is harmless, but unnecessary. The `4' may
be true for your C implementation, but is not universal:
each C implementation chooses its own "best" size for
`int', and different implementations choose differently.
For portability, write `sizeof array[0]' instead.

> for(idx=0; idx<7; ++idx)
> printf("%d\t", array[idx]);
> printf("\n");
>
> return 0;
> }
>
> int compare(const void* a, const void* b)
> {
> if(a < b) return -1;
> if(a == b) return 0;
> if(a > b) return 1;
> }

Here's your difficulty. The comparison function's
arguments are not two array elements, but pointers to
two array elements. You are comparing the pointers, but
you want to compare the pointed-to objects. Here is one
way to do it:

int compare(const void *a, const void *b) {
int u = *(const int*)a;
int v = *(const int*)b;
if (u < v) ...

--
Eric.Sosman@sun.com

 Trent Buck 11-17-2004 07:31 PM

Re: qsort

Quoth John Smith on or about 2004-11-17:
> if(a < b) return -1;
> if(a == b) return 0;
> if(a > b) return 1;

First of all, shouldn't these be dereferenced?

 Andrey Tarasevich 11-17-2004 07:42 PM

Re: qsort

John Smith wrote:
> I'm trying to figure out qsort(). I haven't seen any practical examples,
> only synopsis. In the code below, the array is not sorted. Can someone
> give me some help?
>
> #include <stdio.h>
> #include <stdlib.h>
> int compare(const void* a, const void* b);
>
> int main(void)
> {
> int idx;
> int array[] = {243, 12, 99, 106, 122, 77, 242};
>
> qsort(array, 7, 4, &compare);
> for(idx=0; idx<7; ++idx)
> printf("%d\t", array[idx]);
> printf("\n");
>
> return 0;
> }
>
> int compare(const void* a, const void* b)
> {
> if(a < b) return -1;
> if(a == b) return 0;
> if(a > b) return 1;
> }

of comparing the values pointed by those pointers. You are supposed to
do the latter, not the former. For example, you can do it as follows

int compare(const void* a, const void* b)
{
int ia = *(const int*) a;
int ib = *(const int*) b;
return (ia > ib) - (ia < ib);
}

Also, it makes more sense to form arguments of 'qsort' by using
'sizeof', instead of specifying concrete values explicitly

qsort(array, sizeof array / sizeof *array, sizeof *array, &compare);

--
Best regards,
Andrey Tarasevich

 pete 11-18-2004 11:15 AM

Re: qsort

John Smith wrote:
>
> I'm trying to figure out qsort(). I haven't seen any practical examples,
> only synopsis. In the code below, the array is not sorted. Can someone
> give me some help?
>
> #include <stdio.h>
> #include <stdlib.h>
> int compare(const void* a, const void* b);
>
> int main(void)
> {
> int idx;
> int array[] = {243, 12, 99, 106, 122, 77, 242};
>
> qsort(array, 7, 4, &compare);
> for(idx=0; idx<7; ++idx)
> printf("%d\t", array[idx]);
> printf("\n");
>
> return 0;
> }
>
> int compare(const void* a, const void* b)
> {
> if(a < b) return -1;
> if(a == b) return 0;
> if(a > b) return 1;
> }

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

#define NELM (sizeof array / sizeof *array)

int compare(const void* a, const void* b);

int main(void)
{
int idx;
int array[] = {243, 12, 99, 106, 122, 77, 242};

qsort(array, NELM, sizeof *array, compare);
for (idx = 0; idx < NELM; ++idx) {
printf("%d\t", array[idx]);
}
putchar('\n');
return 0;
}

int compare(const void* a, const void* b)
{
const int aa = *(int*)a;
const int bb = *(int*)b;

return bb > aa ? -1 : aa > bb;
}

--
pete

 Robert Harris 11-18-2004 12:10 PM

Re: qsort

pete wrote:

> [snip]

> int compare(const void* a, const void* b)
> {
> const int aa = *(int*)a;

should be:
const int aa = *(const int *)a;
> const int bb = *(int*)b;
>
> return bb > aa ? -1 : aa > bb;

return aa - bb;

would be the usual idiom.
> }
>

 pete 11-18-2004 12:18 PM

Re: qsort

Robert Harris wrote:
>
> pete wrote:
>
> > [snip]

>
> > int compare(const void* a, const void* b)
> > {
> > const int aa = *(int*)a;

> should be:
> const int aa = *(const int *)a;

It makes no difference.
You wind up with const int aa, either way.

> > const int bb = *(int*)b;
> >
> > return bb > aa ? -1 : aa > bb;

> return aa - bb;
>
> would be the usual idiom.

(aa - bb) is entirely unacceptable
as a generic compar function expression.
If aa equals INT_MAX and bb equals -1,
then you have undefined behavior.

> > }

--
pete

 Charlie Gordon 11-18-2004 02:42 PM

Re: qsort

"John Smith" <JSmith@mail.net> wrote in message
news:5qNmd.252445\$%k.66766@pd7tw2no...
> I'm trying to figure out qsort(). I haven't seen any practical examples,
> only synopsis. In the code below, the array is not sorted. Can someone
> give me some help?

> int compare(const void* a, const void* b)
> {
> if(a < b) return -1;
> if(a == b) return 0;
> if(a > b) return 1;
> }

The compare function is incorrect.
Other replies have given correct alternatives.
Here is my question :

What is the semantics of comparing void* for anything but equality ?
It is non standard to subtract void pointers (but a dubious gcc extension)
What about comparison ? Is it also an extension or is it defined in the
standard ?

Chqrlie.

 Eric Sosman 11-18-2004 03:58 PM

Re: qsort

Charlie Gordon wrote:
> "John Smith" <JSmith@mail.net> wrote in message
> news:5qNmd.252445\$%k.66766@pd7tw2no...
>>
>>int compare(const void* a, const void* b)
>>{
>> if(a < b) return -1;
>> if(a == b) return 0;
>> if(a > b) return 1;
>>}

>
> The compare function is incorrect.
> Other replies have given correct alternatives.
> Here is my question :
>
> What is the semantics of comparing void* for anything but equality ?
> It is non standard to subtract void pointers (but a dubious gcc extension)
> What about comparison ? Is it also an extension or is it defined in the
> standard ?

The comparison is well-defined (as I learned to my
surprise not long ago) under the usual condition that
the two pointers point to or just after the same array.
qsort() guarantees this (although bsearch() obviously
does not), so the comparison is valid.

However, the fact that the comparison is valid doesn't
imply that it's usable by qsort()! The compare() function
must define a consistent ordering, even while qsort() is
busy rearranging the array. If the compare() function's
result changes as the items are shuffled about, the ordering
is inconsistent and qsort()'s behavior is undefined.

Various people have run afoul of this by trying to
compare the pointers to equal elements in an attempt to
achieve a stable sort, e.g.

int compare(const void *p, const void *q) {
int a = *(const int*)p;
int b = *(const int*)q;

if (a < b) return -1;
if (a > b) return +1;

/* Equal elements; try for stability */
if (p < q) return -1;
if (p > q) return +1;
return 0; /* stupid qsort()! */
}

is wrong, R-O-N-G, wrong. The outcome of comparing two
equal integers would depend on their relative locations
in the array, and these locations can change as qsort()
does its work.

--
Eric.Sosman@sun.com

 Andrey Tarasevich 11-18-2004 04:30 PM

Re: qsort

Robert Harris wrote:
> ...
>> int compare(const void* a, const void* b)
>> {
>> const int aa = *(int*)a;

> should be:
> const int aa = *(const int *)a;
>> const int bb = *(int*)b;
>>
>> return bb > aa ? -1 : aa > bb;

> return aa - bb;
>
> would be the usual idiom.

The usual idiom would be

return (aa > bb) - (aa < bb);

A mere 'aa - bb' can produce signed overflow, which makes it entirely
useless.

--
Best regards,
Andrey Tarasevich

All times are GMT. The time now is 04:20 PM.