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


entry.  (There is a static storage class for  mak-
ing local variables with memory; we won't discuss it.)

     As opposed to local variables, external  variables  are
defined  external  to  all  functions, and are (potentially)
available to all functions.  External storage always remains
in  existence.  To make variables external we have to define
them external to all functions, and, wherever we want to use
them, make a declaration.

     main( ) {
             extern int nchar, hist[ ];
             ...
             count( );
             ...
     }

     count( ) {
             extern int nchar, hist[ ];
             int i, c;
             ...
     }

     int     hist[129];      /* space for histogram */
     int     nchar;          /* character count */


Roughly speaking, any function  that  wishes  to  access  an
external variable must contain an extern declaration for it.
The declaration is the same as others, except for the  added
keyword  extern.   Furthermore,  there  must  somewhere be a
definition of the external variables external to  all  func-
tions.

     External variables can be initialized; they are set  to
zero  if  not explicitly initialized.  In its simplest form,
initialization is done by putting the value (which must be a
constant) after the definition:

     int     nchar   0;
     char    flag    'f';

       etc.

This is discussed further in a later section.


     This ends our discussion of what might  be  called  the
central  core of C.  You now have enough to write quite sub-
stantial C programs, and it would probably be a good idea if
you  paused long enough to do so.  The rest of this tutorial
will describe some more ornate constructions, useful but not
essential.

16. Pointers


     A pointer in C is the address of something.   It  is  a
rare  case  indeed  when  we  care what the specific address
itself is, but pointers are a quite common way to get at the
contents  of  something.   The unary operator `&' is used to
produce the address of an object, if it has one. Thus

             int a, b;
             b = &a;


puts the address of a into b.  We  can't  do  much  with  it
except print it or pass it to some other routine, because we
haven't given b the right kind of declaration.   But  if  we
declare  that  b is indeed a pointer to an integer, we're in
good shape:

             int a, *b, c;
             b = &a;
             c = *b;


b contains the address of a and `c = *b' means  to  use  the
value in b as an address, i.e., as a pointer.  The effect is
that  we  get  back  the  contents  of  a,   albeit   rather
indirectly.  (It's always the case that `*&x' is the same as
x if x has an address.)

     The most frequent use of pointers in C is  for  walking
efficiently along arrays.  In fact, in the implementation of
an array, the array  name  represents  the  address  of  the
zeroth element of the array, so you can't use it on the left
side of an expression.  (You can't  change  the  address  of
something by assigning to it.) If we say

     char *y;
     char x[100];


y is of type pointer to character (although it  doesn't  yet
point  anywhere).  We can make y point to an element of x by
either of

     y = &x[0];
     y = x;


Since x is the address of x[0] this is legal and consistent.

     Now `*y' gives x[0].  More importantly,

     *(y+1)  gives x[1]
     *(y+i)  gives x[i]


and the sequence

             y = &x[0];
             y++;


leaves y pointing at x[1].

     Let's use pointers in a function length  that  computes
how  long a character array is.  Remember that by convention
all character arrays are terminated with a  `\0'.   (And  if
they  aren't, this program will blow up inevitably.) The old
way:

     length(s)
        char s[ ]; {
             int n;
             for( n=0; s[n] != '\0'; )
                     n++;
             return(n);
     }


Rewriting with pointers gives

     length(s)
        char *s; {
             int n;
             for( n=0; *s != '\0'; s++ )
                     n++;
             return(n);
     }


You can now see why we have to say  what  kind  of  thing  s
points  to  _  if  we're to increment it with s++ we have to
increment it by the right amount.

     The pointer version is more efficient (this  is  almost
always true) but even more compact is

             for( n=0; *s++ != '\0'; n++ );

The `*s'  returns  a  character;  the  `++'  increments  the
pointer  so  we'll  get the next character next time around.
As you can see, as we make things more  efficient,  we  also
make them less clear.  But `*s++' is an idiom so common that
you have to know it.

     Going a step further, here's our function strcopy  that
copies a character array s to another t.

     strcopy(s,t)
        char *s, *t; {
             while(*t++ = *s++);
     }


We have omitted the  test  against  `\0',  because  `\0'  is
identically  zero;  you  will  often  see the code this way.
(You MUST have a space after the `=': see section 25.)

     For arguments  to  a  function,  and  there  only,  the
declarations

     char s[ ];
     char *s;


are equivalent _ a  pointer  to  a  type,  or  an  array  of
unspecified size of that type, are the same thing.

     If this all seems mysterious, copy  these  forms  until
they  become  second  nature.  You don't often need anything
more complicated.

17. Function Arguments


     Look back at the function strcopy in the previous  sec-
tion.  We passed

Page : << Previous 6  Next >>