[comp.unix.xenix] qsort

root@ozdaltx.UUCP (root) (02/12/90)

After going over the manuals more times than I'd like, I still can't
figure out how to get qsort() (S) to operate.  The example shows
something like:

	void qsort(base, nel, width, compar)
	char *base
	unsigned nel, width
	int (*compar)()

Is base supposed to be an array?
nel & width are self-explanitory
What is compar() looking for or how is it assigned?


The objective is to sort an array of strings in alpha order and then
be able to read them.  So far I'm getting is core dumps.

Any help, suggestions will be appreciated.
thanks
Scotty
------
AIDS INFORMATION EXCHANGE BBS      (214) 247-2367/247-5609
               "Education is the best weapon"
     {ames,rutgers,texsun,smu}!attctc!ozdaltx!sysop 

vp@fctunl.rccn.pt (Vasco Pedro) (02/13/90)

In article <5916@ozdaltx.UUCP> root@ozdaltx.UUCP (root) writes:
>
>	   void qsort(base, nel, width, compar)
>	   char *base
>	   unsigned nel, width
>	   int (*compar)()
>
>   Is base supposed to be an array?
>   nel & width are self-explanitory
>   What is compar() looking for or how is it assigned?
>

Yep, 'base' is supposed to the be the (char *)base of the array you
intend to sort. 'nel' is the number of elements to be sorted and
'width' the sizeof(element_to_sort).
'compar' is a pointer to int function that must behave like
strcmp(s1,s2) a that will be called by qsort(...), for each two
elements that will be compared, ie, if elements 2 and 4 need be
compared there will be a call of the form:

		compar(base+(2-1)*width, base+(4-1)*width).

If is strings you want to sort might just call (I think):

		qsort(array,nel,width,strcmp).

Sorry for the inaccuracies and hope this helps.
--
---
Vasco Pedro			    BITNET/Internet: vp@host.fctunl.rccn.pt
Phone: (+351) (1) 295-4464 (1360)   ARPA: vp%hara.fctunl.rccn.pt@mitvma.mit.edu
Fax: (+351) (1) 295-4461	    PSI/VMS: PSI%(+2680)05010310::HOST::vp
				    UUCP: ...mcvax!inesc!unl!vp
Snail:	Dept. de Informatica, Universidade Nova de Lisboa
	2825 Monte Caparica, PORTUGAL

jha@spodv5.UUCP (Johan Harsta) (02/13/90)

In article <5916@ozdaltx.UUCP>, root@ozdaltx.UUCP (root) writes:
> After going over the manuals more times than I'd like, I still can't
> figure out how to get qsort() (S) to operate.  The example shows
> something like:
> 
> 	void qsort(base, nel, width, compar)
> 	char *base
> 	unsigned nel, width
> 	int (*compar)()
> 
> Is base supposed to be an array?
	- 'base' should be a pointer to the base of the table, and of type
	pointer to an element in the table, casted to a pointer to character
> nel & width are self-explanitory
> What is compar() looking for or how is it assigned?
	- 'compar' is supplied by you; e.g. 'strcmp' or a modified version
	of it

E.g.:
	struct ELEMENT buffer[nele];

	sort_buf (&buffer[0], nele);

	void
	sort_buffer (base, nele)
		struct ELEMENT *base;
		int nele;
	{	
		qsort ((char *) base, 
			(unsigned) nele, 
			(unsigned) sizeof (struct ELEMENT),
			sorting_alg);
		return;
	}

	int
	sorting_alg (arg1, arg2)
		char *arg1;
		char *arg2;
	{
		return (strncmp (arg1, arg2, MAX_RELEVANT_CHARACTERS));
	}

	Something like the above should work, good luck!	

	/Johan Harsta, Programator Uppsala AB, Sweden (consultant for Philips)

gegu@bii.UUCP (Gerhard Gucher) (02/13/90)

In article <5916@ozdaltx.UUCP>, root@ozdaltx.UUCP (root) writes:
> After going over the manuals more times than I'd like, I still can't
> figure out how to get qsort() (S) to operate.  The example shows
> something like:
> 
> 	void qsort(base, nel, width, compar)
> 	char *base
> 	unsigned nel, width
> 	int (*compar)()
> 
> Is base supposed to be an array?
> nel & width are self-explanitory
> What is compar() looking for or how is it assigned?
> 
> 
> The objective is to sort an array of strings in alpha order and then
> be able to read them.  So far I'm getting is core dumps.
> 

qsort is a little bit tricky for arrays of strings. compar() will
get the address of two items to be sorted as arguments. Since your
arguments are strings (char*'s) you must supply a compare function
which accepts (char**)'s as args.
The Example has been tested on a SUN OS 4.03 cc compiler.

Example:

#define NUM_ELEM(a)	( sizeof(a)/sizeof(a[0]) )

/* array to be sorted */
char * array[] = { "beta", "gamma", "alpha", "delta", "epsilon" };

extern int qsort();

/****************************************************************/
int ind_strcmp(s,t)	/* indirect string compare for qsort */
char** s;
char** t;
{
  return( strcmp(*s,*t) );
}


/****************************************************************/
/* ARGSUSED */
int
main(argc,argv)
int argc;
char *argv[];
{
  int i;

  (void) qsort( (char*)(&array[0]), 
         NUM_ELEM(array), 
         sizeof(array[0]),
         ind_strcmp		/* gets the address of the char ptrs */
  );

  /* print the sorted array */
  for( i=0; i< NUM_ELEM(array); i++ )
    (void)printf( "%s\n", array[i] );

} /* main() */

--
+------------------------------------------------------------------+
| Gerry Gucher    uunet!bii!gegu       gegu@bii.bruker.com	   |
| Bruker Instruments Inc. Manning Park Billerica MA 01821          | 
+------------------------------------------------------------------+

david@csource.oz.au (David Nugent) (02/14/90)

 > From: root@ozdaltx.UUCP (root)
 > Date: 12 Feb 90 14:55:54 GMT
 > Organization: OZ BBS - Dallas, TX
 > Message-ID: <5916@ozdaltx.UUCP>
 >
 >         void qsort(base, nel, width, compar)
 >         char *base
 >         unsigned nel, width
 >         int (*compar)()
 >
 > Is base supposed to be an array?


 
Yes.
 

 > nel & width are self-explanitory
 > What is compar() looking for or how is it assigned?
 
compar() is the address of a compare function.  It's prototype is 
something like:
 
  int compar (char *, char *);
 
 > The objective is to sort an array of strings in alpha order
 > and then
 > be able to read them.  So far I'm getting is core dumps.
 
 
Well, fortunately strcmp() is compatible with the function.  The following 
should work ok:
 
 
  qsort (base, 20, 64, strcmp);
 
This would sort an array of strings placed in an array of 64 bytes 
(size of each element), and sort twenty elements into alpha order.
 
 
david


--  
UUCP: ...!munnari!csource!david
INTERNET: david@csource.oz.au
Via FidoNet 3:632/348, Central Source ICBS, Melbourne, Australia

ryan@sjuphil.uucp (Patrick M. Ryan) (02/14/90)

In article <5916@ozdaltx.UUCP> root@ozdaltx.UUCP (root) writes:
>After going over the manuals more times than I'd like, I still can't
>figure out how to get qsort() (S) to operate.  The example shows
>something like:
>
>	void qsort(base, nel, width, compar)
>	char *base
>	unsigned nel, width
>	int (*compar)()
>
>Is base supposed to be an array?
>nel & width are self-explanitory
>What is compar() looking for or how is it assigned?
>
>The objective is to sort an array of strings in alpha order and then
>be able to read them.  So far I'm getting is core dumps.

    yes, base is supposed to be an array.  compar() takes two pointers
to structures to compare. compare must return an integer (say, ret) to
indicate the order of the two items. ret = 0 if they are equal, ret < 0
if the first item is less than the second, and ret > 1 other wise.

ex:

#define LEN  32
#define MAX 512

char str[LEN][MAX];
int compare();

main()
{
    .
    .
    .

    qsort(str,MAX,LEN,compare);
    .
    .

}

int compare(s1,s2)
char *s1, *s2;
{
    return(strcmp(s1,s2));
}

-- 
patrick m. ryan
  ryan%sjuphil.sju.edu@bpa.bell-atl.com
  {bpa|burdvax|princeton|rutgers}!sjuphil!ryan
  pmr@gemini.gsfc.nasa.gov

root@ozdaltx.UUCP (root) (02/14/90)

Just want to say THANKS TO ALL the many responces I received about
qsort().  I know I can always count on the net.gurus to clairify or
help with a problem.  It is fustrating when the manuals are poorly
written without decent examples, seems as if one almost has to know
how something works before reading up on it.  Too much is assumed by
the manual writters.

I'll post a summery of responces in the next day or so, maybe someone
else will bebefit for it.
Scotty
------
AIDS INFORMATION EXCHANGE BBS      (214) 247-2367/247-5609
               "Education is the best weapon"
     {ames,rutgers,texsun,smu}!attctc!ozdaltx!sysop 

daved@physiol.su.oz (Dave Davey) (02/15/90)

jha@spodv5.UUCP (Johan Harsta) writes:

|In article <5916@ozdaltx.UUCP>, root@ozdaltx.UUCP (root) writes:
|> After going over the manuals more times than I'd like, I still can't
|> figure out how to get qsort() (S) to operate.  The example shows

|E.g.:
|	struct ELEMENT buffer[nele];

|	sort_buf (&buffer[0], nele);

|	void
|	sort_buffer (base, nele)
|		struct ELEMENT *base;
|		int nele;
|	{	

					/*****************************/
		int sorting_alg();	/**** needs this declaration */
					/*****************************/

|		qsort ((char *) base, 
|			(unsigned) nele, 
|			(unsigned) sizeof (struct ELEMENT),
|			sorting_alg);
|		return;
|	}

msb@sq.sq.com (Mark Brader) (02/21/90)

> >	   void qsort(base, nel, width, compar)
> >	   char *base
> >	   unsigned nel, width
> >	   int (*compar)()
> Yep, 'base' is supposed to the be the (char *)base of the array you
> intend to sort. 'nel' is the number of elements to be sorted and
> 'width' the sizeof(element_to_sort).
> 'compar' is a pointer to int function that must behave like strcmp...
> If is strings you want to sort might just call (I think):
> 		qsort(array,nel,width,strcmp).

This is correct as far as it goes but there is a tricky point that
must be emphasized.  The compar function that you provide will be
called with arguments that *point to* the elements of the array.
(It works this way because the array elements might have a type that
cannot be passed efficiently, or at all, as a function argument.)

Therefore, if you have a 2-dimensional array of chars where each row
is used to contain a string, like this:

	char place[][MAXLEN+1] = {"Portugal", "Canada", "Paraguay", "Japan"};

then you can indeed sort it with

	#define NUMEL(x) (sizeof x / sizeof *x)
	int strcmp();
	qsort ((char *) place, NUMEL (place), sizeof *place, strcmp);

However, if your array itself contains pointers, like this:

	char *place[] = {"Portugal", "Canada", "Paraguay", "Japan"};

then you must define a function

	int
	indstrcmp (sp1, sp2)
	char *sp1, *sp2;
	{
		return strcmp ( * (char **) sp1,  * (char **) sp2);
	}

The arguments to indstrcmp() have to be declared as char * rather than
char **, and then converted to char **,, because char * is what qsort()
is going to pass to indstrcmp().

and invoke qsort using it:

	qsort ((char *) place, NUMEL (place), sizeof *place, indstrcmp);


All of the above is in pre-ANSI style.  In ANSI C, void * rather than char *
is used as the generic pointer type (but they're represented the same way
and passed the same way to functions, so strcmp() will work on void *'s).
So the first example becomes:

	qsort ((void *) place, NUMEL (place), sizeof *place, strcmp);

and the second one:

	int
	indstrcmp (const void *sp1, const void *sp2)
	{
		return strcmp ( * (char **) sp1, * (char **) sp2);
	}
and:
	qsort ((void *) place, NUMEL (place), sizeof *place, indstrcmp);

Followups are directed to comp.lang.c.
-- 
Mark Brader			"[This computation] assumed that everything
SoftQuad Inc., Toronto		 would work, a happy state of affairs found
utzoo!sq!msb, msb@sq.com	 only in fiction."	-- Tom Clancy

This article is in the public domain.