Using Some of the C Library Functions

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

footnote: Check our optional text, or type man strcpy for more information.
.

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

Norm Matloff
Wed Nov 8 17:30:46 PST 1995