summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SAWTELL/c-lesson.7
blob: d5caba1d481a70f394a5e79097009b958a0bfe29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

Lesson 6

          Libraries, why we have them, and how to make and use them.

  In order to simplify the creation of programs for its customers,
software vendors make available one or more libraries of functions
which have general application.

        When you write a program in 'C' much, if not most, of the "hard work"
is done by explicitly called functions, which you call by simply writing
their names in your program script. Unfortunately there is a little bit
more to it than that. If the function returns a value which is other
than of type int, you have to tell the compiler the type of the returned
value. An example will, I hope make things clear.

        Lets's suppose that you have been given the task of, making things
stupidly simplistic for a book example, sorting a list of names into
alphabetical order. ( Yes, I do know this can, and should be done in just
one line of shell script! However that's another story for another day. )

        You look diligently through the Programmer Reference Manual, discover
that the prose is almost opaque, and find a couple of interesting looking
routines called strcmp, and qsort. You decide to use these library
functions. Now for just a moment lets consider the ins and outs of what,
in effect, you have just done. You have just asked a member of the team
of programmers who created the library to join you, by proxy as it were, in
creating your masterpiece. A useful concept, which has been in use
almost since the start of electronic computing.

        To re-focus the mind on the task at hand; let's look in the Reference
Manual
at the page for qsort(3C) - The 3C in parenthesis is the cryptic code which
is the unix apology for a reference to section 3C in the Manual! So find
section 3C and look up qsort. Now have a look at the SYNOPSIS, and notice
that there is no mention of a header file to #include, and also notice that
qsort returns a void, not an int. This means that there is no header file
/usr/include/qsort.h ( for my version of unix - system V Release 3.2.2 -
anyway ) and you have to declare qsort yourself as an external function.
Also turn to the page string(3C) in the fine manual. Notice that the
SYNOPSIS here includes the line #include <string.h> so you have to put
it in your program text. Once more an example to make it all clear.


/* ----------------------------------------- */

#ident "@(#) qsort-demo.c"

#include <stdio.h>
#include <string.h>
#include <assert.h>

extern void qsort ();
extern int strcmp();        /* Some compilers need this defined, most don't. */

char names[22][25] =                         /* Here are some names to sort. */
{
  "John Nagle", "Colin Douthwaite", "Ian Lance Taylor", "Brian J. Murrell",
  "Pete", "Geoff Mccaughan", "David Liebert", "Operator", "Bill Baucum",
  "Victor Volkman", "Chay R Harley", "Dan Romanchik", "Larry Kollar",
  "Gaston Ormazabal", "Arijit Chandra", "Kenneth Mark Hopkinson",
  "Kerr Hatrick", "Tim Love", "Robert M. Juranitch", "Jeffrey Micke",
  "Duong Quoc", "Jagadesh Vasudevamurthy"
        };

#define NUMBER_OF_NAMES sizeof ( names ) / sizeof ( names[0] )

main()
{
  int i;

        /*
        ** Print the unsorted names.
        */

        printf ( "The Unsorted Names.\n" );
  for ( i = 0; i < NUMBER_OF_NAMES; i++ ) printf ( "%s\n", names[i] );

        /*
        ** Print a prompt, and wait.
        */

        printf ( "Press RETURN to continue: " );
        fflush ( stdout );
        getchar();

        /*
        ** Now apply qsort to the arrary of character strings.
        */

        qsort (( char * ) names, NUMBER_OF_NAMES, sizeof ( *names ), strcmp );

        assert ( names[0][0] < names[1][0] );  /* Quick check to see it's done
it. */

        /*
        ** Print the sorted names.
        */

        printf ( "The Sorted Names.\n" );
  for ( i = 0; i < NUMBER_OF_NAMES; i++ ) printf ( "%s\n", names[i] );
  }

/* ----------------------------------------- */

  Note very well:-

        I wanted 22 short character strings for the data items
for the demo to sort. So grep, uniq, cut, tail, and finally a tiny bit of
vi fished eminently suitable strings out of "mail.received". If your name
is not on the list, well I'm sorry, but the world is not a fair place!

  So that's how you use library routines. I chose qsort because it is
simple to use, and shows off a feature of 'C' well, that's the ability
to use a name of a function as a pointer and then execute that function
from within the called function. It's strcmp in this case. A quick look
at the compiler output is instructive.

  As is the nature of the animal, a tin-pot little program, which should
have taken all of ten minutes to get going in fact took more like two
hours. I put it down to the fact that the Fine Manual did not make it
adequately obvious that the data array acted on by qsort was the data itself.
From reading the Fine Manual I got the impression that the array acted on
was an array of pointers. You live and learn. It would be a much faster
qsort if, in fact, the sorting function sorted pointers to data instead of
the data itself. You might like to make a function qsort_p which worked in
in this way. The qsort algorithm is well documented elsewhere.

        There is just one more point to notice about using function libraries.
The 'C' compilation system will load functions from the library /lib/libc.a
as a default. All others have to be indicated to the linking loader by a
switch on the shell interactive command line.

$ cc -o prog prog.c -L /usr/local/lib -lgdbm -lmalloc

        You might use this command line to compile and link a program which
uses both the GNU gdbm data-base manager library, which is installed in
the directory /usr/local/lib, and the enhanced malloc library. Now, there
hangs a tale! I remember having to compile a program suit off Usenet and
it just would not work properly. No error messages, no warnings, no
missing linking-loader symbols. It just "died" when I tried to run it.
After many, many hours of total frustration, I thought that I would try
linking in the enhanced malloc library. Presto! It worked.

        Note very well.

  A common misconception is the notion that having a #include <whatever.h>
line in the source text will automagically tell the linking loader to
get the functions from the appropriate library. Remove this erroroneous
notion from your mind. It won't. The -lwhatever flag on the shell command
line which initiates execution of "cc" or "ld" is the only way to tell the
loader where to look for the required library.


--
 +----------------------------------------------------------------------+
 | NAME   Christopher Sawtell                                           |
 | SMAIL  215 Ollivier's Road, Linwood, Christchurch, 8001. New Zealand.|
 | EMAIL  chris@gerty.equinox.gen.nz                                    |
 | PHONE  +64-3-389-3200   ( gmt +13 - your discretion is requested )   |
 +----------------------------------------------------------------------+