Topic : Programming In C
Author : Brian Kernighan
Page : << Previous 10  Next >>
Go to page :


compar(s, p->id) > 0)
                             return(p);
             return(0);
     };



The function compar doesn't  change:  `p->id'  refers  to  a
string.

     In main we test the pointer returned by lookup  against
zero,  relying  on  the fact that a pointer is by definition
never zero when it really points at  something.   The  other
pointer manipulations are trivial.

     The only complexity is the set of lines like

     struct symtag *lookup( );

This brings us to an area that we will treat only  hurriedly
_  the question of function types.  So far, all of our func-
tions have returned integers (or characters, which are  much
the  same).   What  do we do when the function returns some-
thing else, like a pointer to a structure?  The rule is that
any  function  that  doesn't return an int has to say expli-
citly what it does return.  The type information goes before
the  function  name  (which  can make the name hard to see).
Examples:

     char f(a)
        int a; {
             ...
     }

     int *g( ) { ... }

     struct symtag *lookup(s) char *s; { ... }


The function f returns a character, g returns a  pointer  to
an integer, and lookup returns a pointer to a structure that
looks like symtag.  And if we're going to use one  of  these
functions, we have to make a declaration where we use it, as
we did in main above.

     Notice th parallelism between the declarations

             struct symtag *lookup( );
             struct symtag *psym;



In effect, this says that lookup( ) and psym are  both  used
the  same way _ as a pointer to a strcture _ even though one
is a variable and the other is a function.

21. Initialization of Variables


     An external variable may be initialized at compile time
by  following its name with an initializing value when it is
defined.  The initializing value has to be  something  whose
value is known at compile time, like a constant.

     int     x       0;      /* "0" could be any constant */
     int     a       'a';
     char    flag    0177;
     int     *p      &y[1];  /* p now points to y[1] */


An external array can be initialized by following  its  name
with a list of initializations enclosed in braces:

     int     x[4]    {0,1,2,3};        /* makes x[i] = i */
     int     y[ ]    {0,1,2,3}; /* makes y big enough for 4 values */
     char    *msg    "syntax error\n"; /* braces unnecessary here */
     char *keyword[ ]{
             "if",
             "else",
             "for",
             "while",
             "break",
             "continue",
             0
     };


This last one is very useful _ it makes keyword an array  of
pointers  to character strings, with a zero at the end so we
can identify the last element easily.  A simple lookup  rou-
tine  could  scan  this  until  it  either  finds a match or
encounters a zero keyword pointer:

     lookup(str)             /* search for str in keyword[ ] */
        char *str; {
             int i,j,r;
             for( i=0; keyword[i] != 0; i++) {
                 for( j=0; (r=keyword[i][j]) == str[j] && r != '\0'; j++ );
                  if( r == str[j] )
                           return(i);
             }
             return(-1);
     }



     Sorry _ neither local variables nor structures  can  be
initialized.

22. Scope Rules: Who Knows About What


     A complete C program need not be compiled all at  once;
the source text of the program may be kept in several files,
and  previously  compiled  routines  may  be   loaded   from
libraries.  How do we arrange that data gets passed from one
routine to another?  We have already seen how to  use  func-
tion  arguments  and  values,  so let us talk about external
data.  Warning: the words  declaration  and  definition  are
used precisely in this section; don't treat them as the same
thing.

     A major shortcut exists for making extern declarations.
If  the  definition  of a variable appears BEFORE its use in
some function, no extern declaration is  needed  within  the
function.  Thus, if a file contains

     f1( ) { ... }

     int foo;

     f2( ) { ... foo = 1; ... }

     f3( ) { ... if ( foo ) ... }


no declaration of foo is needed  in  either  f2  or  or  f3,
because  the external definition of foo appears before them.
But if f1 wants to use foo, it has to contain  the  declara-
tion

     f1( ) {
             extern int foo;
             ...
     }



     This is true  also  of  any  function  that  exists  on
another  file  _  if  it  wants  foo it has to use an extern
declaration for  it.   (If  somewhere  there  is  an  extern
declaration  for something, there must also eventually be an
external definition of it, or you'll get an ``undefined sym-
bol'' message.)

     There are some hidden pitfalls in external declarations
and  definitions if you use multiple source files.  To avoid
them, first, define and initialize  each  external  variable
only once in the entire set of files:

     int     foo     0;

You can get away with multiple external definitions on UNIX,
but  not  on  GCOS, so don't ask for trouble.  Multiple ini-
tializations are illegal everywhere.  Second, at the  begin-
ning  of any file that contains functions needing a variable
whose definition is in some other file,  put  in  an  extern
declaration, outside of any function:

     extern  int     foo;

     f1( ) { ... }
        etc.



     The #include compiler control  line,  to

Page : << Previous 10  Next >>