Our textbook gives an example of use of the C library function qsort(). That example does not exploit qsort()'s ability to sort nonnumeric objects, so we present an example here. This will also show use of some of the C library string-handling functions.
The example consists of a program to input a bunch of words, and sort them in dictionary-like order--in a non case-sensitive manner, i.e. without distinguishing between upper- and lower-case letters. (See the test run, Lines 85-115 below.)
1 Script started on Wed May 6 18:28:11 1992
2 heather% cat QSortExample.c
3
4
5 /* illustration of the C library function qsort();
6
7 qsort() is a very efficient implementation of the Quicksort
8 (actually Quickersort) algorithm;
9
10 the C library function allows sorting of nonnumerical objects,
11 so the user must supply his/her own comparison function, which
12 defines whether one object is "smaller" than another;
13
14 in our example here, an "object" will be a character string;
15 one string is considered "less than" an other if the first
16 string would come before the second if they were listed in a
17 dictionary (so this is called "lexicographic ordering," from
18 the word "lexicon," which means "dictionary")
19
20 this comparison can be done by the C library function strcmp(),
21 but here we wish to make no distinction between lower- and
22 upper-case letters, so we cannot use strcmp(); thus we are
23 providing our own function instead, MyStrcmp()
24
25 the compare-function has two arguments, which are the addresses
26 of the two items to be compared, and returns an integer value
27 which is either less than 0 (signifying that the first object
28 is "less than" the second), equal to 0 (signifying that the
29 two objects are equal) or greater than 0 (signifying that the
30 first object is greater than the second */
31
32
33 #define MaxNWords 100
34 #define MaxWordLength 20
35
36
37 char Word[MaxNWords][MaxWordLength]; /* array of words to be sorted */
38
39
40 int MyOwnStrcmp(WordPtrA,WordPtrB)
41 char *WordPtrA,*WordPtrB;
42
43 { char LCWord[2][MaxWordLength],C;
44 int UpperVsLowerDiff,I,J;
45
46 /* first, make copies of the two input strings, except that in
47 the copies all upper-case letters have been changed to lower-
48 case */
49 strcpy(LCWord[0],WordPtrA);
50 strcpy(LCWord[1],WordPtrB);
51 UpperVsLowerDiff = 'a' - 'A';
52 for (I = 0; I < 2; I++)
53 for (J = 0; J < MaxWordLength; J++) {
54 C = LCWord[I][J];
55 if (C >= 'A' && C <= 'Z')
56 LCWord[I][J] += UpperVsLowerDiff;
57 }
58
59 /* OK, now we can use the ordinary strcmp() function */
60 return strcmp(LCWord[0],LCWord[1]);
61 }
62
63
64 main()
65
66 { int I,NWords;
67
68 printf("enter words, with ctrl-d to end\n");
69 for (NWords = 0; ; NWords++) {
70 if (scanf("%s",Word[NWords]) == -1) break;
71 }
72
73 /* qsort()'s parameters are:
74 address of the first object
75 number of objects
76 sizeof(object)
77 name of the compare-function */
78 qsort(Word,NWords,MaxWordLength,MyOwnStrcmp);
79 printf("sorted array:\n");
80 for (I = 0; I < NWords; I++) printf("%s\n",Word[I]);
81 }
82
83
84
85 heather% a.out
86 enter words, with ctrl-d to end
87 NBC
88 ABC
89 CBS
90 BART
91 Bart
92 Bartlett
93 West
94 west
95 western
96 next
97 NeXT
98 CA
99 Canada
100 can
101 sorted array:
102 ABC
103 Bart
104 BART
105 Bartlett
106 CA
107 can
108 Canada
109 CBS
110 NBC
111 next
112 NeXT
113 west
114 West
115 western
116 heather% e
117 heather%
118 script done on Wed May 6 18:31:09 1992
Analysis:
Line 37: A two-dimensional array of characters. Word[I][J] is the J-th character of the I-th word. By the way, please note that the I-th word as a whole can be referred to as Word[I]; this is a feature of C, which regards a two-dimensional array as a one-dimensional array of one-dimensional arrays!
Line 70: Here we are reading in the NWords-th word; see the last remark in the analysis for Line 37 above.
Lines 73-78: The comments explain the parameters which qsort() expects; let's call them par0, par1, par2 and par3. Two of them are worth special mention:
Par2 is the size of each ``object'' to be sorted. This is important. All the objects are stored contiguously in memory (as with any array). So in order to access the I-th object, qsort() will go to the address which is I*par2 bytes past the beginning of the array, par0; i.e. the I-th object starts at address par0+I*par2.
Par3 tells qsort() which function we want it to use as the compare-function.
Lines 40ff: Here is our compare-function. Each time qsort() is ready to compare two of the objects (which will occur many times during its execution), it will call our compare-function. The two parameters which it passes to our compare-function will be the addresses of the two objects which it is currently comparing.
What we will do is copy the two words to temporary strings, in which we convert all upper-case letters to lower-case. By doing this, we will be able to take advantage of the C library's strcmp() function, which does compare two strings--which we want--but also does distinguish between upper- and lower-case--which we don't want.
Lines 49-50: The C library provides a string-copy function for us, saving us some work
Line 60: Again, use the strcmp() function which the C library provides as a convenience to us. (Note again the remark at the end of the analysis of Line 37 above.)