The Scope of C variables

One might ask can I do something like this:

#include <stdio.h>

int foo( int x ) ;

main()
{
   int i, j ;

   foo( i ) ;
   printf( "%d %d\n", i, j ) ;
}

int foo( int x )
{
   j = x * x ;
}

in order to set j to be i squared? The answer is no. Whenever a variable is declared inside a function (as i and j) or is a parameter (like x), that name for some memory location exists only inside the function. So j doesn't really exist inside of the function foo(). That is, i and j are local to main() and x is local to foo().

Because of this scoping in C, you don't have to keep track of which variables are in use in which functions and be careful not to have collisions. It is perfectly valid to code one of our earlier examples as:

#include <stdio.h>

void foo( int x ) ;

main()
{
   int x ;

   x = 42 ;
   foo( x ) ;
   printf( "After calling foo: x = %d\n", x ) ;
}

void foo( int x )
{
   x = 101 ;
   printf( "Inside foo: x = %d\n", x ) ;
}

and have the value for x still be 42 after the call to foo(). This also explains why we could make two calls foo( a, b ) and foo( b, a ) where foo() was declared as int foo( int a, int b ). The variable (or parameter) we use is always the one of that name that has been most recently declared.

Global Variables

On some occasions, it is reasonable to declare variables that are outside of any of the functions in a program. Such variables are called global variables and are usually declared before main(). For example, we could write:

#include <stdio.h>

void get_students( void ) ;

int num_stud ;

main()
{
   get_students() ;
   printf( "The number of students is %d\n", num_stud ) ;
}

void get_students( void )
{
   num_stud = 12 ;
}

and we'd find that the program would indeed print out that the number of students was 12.

Just because you can create global variables doesn't mean you should. The basic rule of thumb is:

Don't use global variables.
Some of the reasons are
Using local variables allows you to focus you attention on smaller more manageable pieces of the program. Globals force you to keep track of how they're being used throughout the entire system.
If you're working with other people, you must coordinate who's creating which global variables. It is not valid to create two globals of the same name.
There are programming techniques (namely recursion) that require some separation of multiple instances of the same variable name.
Localizing the effects of algorithm steps reduces the cases of unexpected behavior.
Localizing the effects of algorithm steps makes the program easier for others to understand.
So when is it reasonable to use global variables? There are basically two occasions:
  1. Sometimes one function indirectly calls another where we have no control over the intermediate steps. If the two functions need to communicate, then we generally need global variables. (Such cases represent fairly advanced techniques relative to those you'll be using in this class, but we'll see an example of this in one of the case studies.)
  2. If the entire program is built around some central data and if access to that data is needed in nearly every function and particularly if that is a large data structure, then it makes sense to make such data global.
The basic rule thumb still applies though and these other cases are not likely to come up in the programs you'll be doing for this class.

One last note: We have only scratched the surface of scoping in C. For example, it is possible to declare variables that have scope smaller than a function. You can also position variables somewhere between local to a function and global to the whole program by making them local to a module.

Consider the following program:
#include <stdio.h>

int f1( void ) ;
int f2( int x, int a ) ;

int a ;

main()
{
   int a, b, c ;

   a = 7 ;
   b = f1() ;
   c = f2( a, b ) ;
   printf( "%d %d %d\n", a, b, c ) ;
}

int f1( void )
{
   a = 12 ;
   printf( "%d ", a ) ;
   return( a + 5 ) ;
}

int f2( int x, int a )
{
   printf( "%d ", a ) ;
   return( x * a ) ;
}   
What will be the output it produces?

12 17 7 17 119
12 17 12 17 204
12 7 7 17 119
12 12 7 17 119