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.)