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


   break;
     }


The case statements  label  the  various  actions  we  want;
default  gets done if none of the other cases are satisfied.
(A default is optional; if it isn't there, and none  of  the
cases match, you just fall out the bottom.)

     The break statement in this  example  is  new.   It  is
there  because  the  cases are just labels, and after you do
one of them, you fall through to the next  unless  you  take
some  explicit  action to escape.  This is a mixed blessing.
On the positive side, you can have multiple cases on a  sin-
gle  statement;  we might want to allow both upper and lower

     case 'a':  case 'A':    ...

     case 'b':  case 'B':    ...
      etc.

But what if we just want to get out after doing case  `a'  ?
We  could get out of a case of the switch with a label and a
goto, but this is really ugly.  The break statement lets  us
exit without either goto or label.

     switch( c ) {

     case 'a':
             aflag++;
             break;
     case 'b':
             bflag++;
             break;
      ...
     }
     /* the break statements get us here directly */


The break statement also works in for and while statements _
it causes an immediate exit from the loop.

     The continue statement  works  _o_n_l_y  inside  for's  and
while's;  it  causes  the  next  iteration of the loop to be
started.  This means it goes to the increment  part  of  the
for  and  the  test part of the while.  We could have used a
continue in our example to get on with the next iteration of
the for, but it seems clearer to use break instead.

20. Structures


     The main use of structures is to lump together  collec-
tions  of disparate variable types, so they can conveniently
be treated as a unit.  For example, if  we  were  writing  a
compiler  or  assembler,  we  might need for each identifier
information like its name (a character  array),  its  source
line  number  (an integer), some type information (a charac-
ter, perhaps), and probably a usage count (another integer).

             char    id[10];
             int     line;
             char    type;
             int     usage;



     We can make a structure out of this quite  easily.   We
first  tell  C  what  the structure will look like, that is,
what kinds of things it contains; after that we can actually
reserve  storage  for  it,  either  in the same statement or
separately.  The simplest thing is to define it and allocate
storage all at once:

     struct {
             char    id[10];
             int     line;
             char    type;
             int     usage;
     } sym;



     This defines sym to be a structure with  the  specified
shape;  id,  line,  type and usage are members of the struc-
ture.  The way we refer to  any  particular  member  of  the
structure is

     structure-name . member

as in

             sym.type = 077;
             if( sym.usage == 0 ) ...
             while( sym.id[j++] ) ...
                
etc.

Although the names of structure members never  stand  alone,
they  still have to be unique _ there can't be another id or
usage in some other structure.

     So far we  haven't  gained  much.   The  advantages  of
structures  start to come when we have arrays of structures,
or when we want to pass  complicated  data  layouts  between
functions.   Suppose we wanted to make a symbol table for up
to 100 identifiers.  We could extend our definitions like

             char    id[100][10];
             int     line[100];
             char    type[100];
             int     usage[100];


but a structure lets us rearrange this  spread-out  informa-
tion  so  all the data about a single identifer is collected
into one lump:

     struct {
             char    id[10];
             int     line;
             char    type;
             int     usage;
     } sym[100];


This makes sym an array of structures;  each  array  element
has the specified shape.  Now we can refer to members as

             sym[i].usage++; /* increment usage of i-th identifier */
             for( j=0; sym[i].id[j++] != '\0'; )
...
                etc.

Thus to print a list of all identifiers  that  haven't  been
used, together with their line number,

             for( i=0; i<nsym; i++ )
                     if( sym[i].usage == 0 )
                             printf("%d\t%s\n", sym[i].line, sym[i].id);



     Suppose we now want to write  a  function  lookup(name)
which  will tell us if name already exists in sym, by giving
its index, or that it doesn't, by returning a -1.  We  can't
pass  a structure to a function directly _ we have to either
define it externally, or pass a pointer to  it.   Let's  try
the first way first.

     int     nsym    0;      /* current length of symbol table */

     struct {
             char    id[10];
             int     line;
             char    type;
             int     usage;
     } sym[100];             /* symbol table */

     main( ) {
          


Page : << Previous 8  Next >>