Variables in C – The Scope, Visibility and lifetime of Variables

Variables in C differ in behavior from those in most other languages. For example, in a BASIC program, a variable retains its value throughout the program. It is not always the case in C. It all depends on the ‘storage’ class a variable may assume.

In C not only do all variables have a data type, they also have a storage class. The following variable storage classes are most relevant to functions:

  1. Automatic variables.
  2. External variables.
  3. Static variables.
  4. Register variables.

We shall briefly discuss the scope, visibility and longevity of each of the above class of variables. The scope of variable determines over what region of the program a variable is actually available for use (‘active’).

Longevity refers to the period during which a variable retains a given value during execution of a program (‘alive’). So longevity has a direct effect on the utility of a given variable. The visibility refers to the accessibility of a variable from the memory.

The variables may also be broadly categorized, depending on the place of their declaration, as internal (local) or external (global). Internal variables are those which are declared within a particular function, while external variables are declared outside of any function.

It is very important to understand the concept of storage classes and their utility in order to develop efficient multifunction programs.

Automatic Variables in C

Automatic variables are declared inside a function in which they are to be utilized. They are created when the function is called and destroyed automatically when the function is exited, hence the name automatic.

Automatic variables are therefore private (or local) to the function in which they are declared. Because of this property, automatic variables are also referred to as local or internal variables.

A variable declared inside a function without storage class specification is, by default, an automatic variable. For instance, the storage class of the variable number in the example below is automatic.

main()
{
int number;
—–
—–
}
We may also use the keyword auto to declare automatic variables explicitly.
main()
{
auto int number;
—–
—–
}

One important feature of automatic variables is that their value cannot be changed accidentally by what happens in some other function in the program.

This assures that we may declare and use the same variable name in different functions in the same program without causing any confusion to the compiler.

Write a multifunction to illustrate how automatic variables work.

A program with two subprograms function1 and function2 is shown in Fig. m is an automatic variable and it is declared at the beginning of each function.

m is initialized to 10, 100, and 1000 in function1, function2, and main respectively.

When executed, main calls function2 which in turn calls function1. When main is active, m = 1000; but when function2 is called, the main’s m is temporarily put on the shelf and the new local m = 100 becomes active.

Similarly, when function1 is called, both the previous values of m are put on the shelf and the latest value of m (=10) becomes active. As soon as function1 (m=10) is finished, function2 (m=100) takes over again.

As soon it is done, main (m=1000) takes over. The output clearly shows that the value assigned to m in one function does not affect its value in the other functions; and the local value of m is destroyed when it leaves a function.

Program
          void function1(void);
          void function2(void);
          main()
          {
               int m = 1000;
               function2();

               printf("%d\n",m); /* Third output */
          }
          void function1(void)
          {
          int m=10;
          printf("%d\n",m); /* First output */
          }
          
          void function2(void)
          {
               int m = 100;
               function1();
               printf("%d\n;m); /* Second output */
          }
Output
          10
          100
          1000

There are two consequences of the scope and longevity of auto variables worth remembering. First, any variable local to main will be normally alive throughout the whole program, although it is active only in main.

Secondly, during recursion, the nested variables are unique auto variables, a situation similar to function-nested auto variables with identical names.

External Variables in C

Variables that are both alive and active throughout the entire program are known as external variables. They are also known as global variables. Unlike local variables, global variables can be accessed by any function in the program. External variables are declared outside a function.

For example, the  External declaration of integer number and float length might appear as:

int number;
float length = 7.5;
main()
{
—–
—–
}
function1()
{
—–
—–
}
function2()
{
—–
—–
}

The variables number and length are available for use in all the three functions. In case a local variable and a global variable have the same name, the local variable will have precedence over the global one in the function where it is declared. Consider the following example:

int count;
main()
{
count = 10;
—–
—–
}
function()
{
int count = 0;
—–
—–
count = count+1;
}

When the function references the variable count, it will be referencing only its local variable, not the global one. The value of count in main will not be affected.

A program to illustrate the properties of global variables is presented in Fig. Note that variable X is used in all functions but none except fun2, has a definition for X. Because x has been declared ‘above’ all the functions, it is available to each function without having to pass x as a function argument.

Further, since the value of x is directly available, we need not use return(x) statements in fun1 and fun3.

However, since fun2 has a definition of x, it returns its local value of x and therefore uses a return statement. In fun2, the global x is not visible. The local x hides its visibility here.

Program
     int fun1(void);
     int fun2(void);
     int fun3(void);
     int x ;     /* global */
     main()
     {
          x = 10 ;   /* global x */
          printf("x = %d\n", x);
          printf("x = %d\n", fun1());
          printf("x = %d\n", fun2());
          printf("x = %d\n", fun3());
     }
     fun1(void)
     {
         x = x + 10 ;
     }
     int fun2(void)
     {
     int x ;      /* local */
     x = 1 ;
     return (x);
     }
     fun3(void)
     {
          x = x + 10 ;  /* global x */
     }
Output
     x = 10
     x = 20
     x = 1
     x = 30

Once a variable has been declared as global, any function can use it and change its value. Then, subsequent functions can reference only that new value.

Global Variables as Parameters

Since all functions in a program source file can access global variables, they can be used for passing values between the functions. However, using global variables as parameters for passing values poses certain problems.

  • The values of global variables which are sent to the called function may be changed inadvertently by the called function.
  • Functions are supposed to be independent and isolated modules. This character is lost, if they use global variables.
  • It is not immediately apparent to the reader which values are being sent to the called function.
  • A function that uses global variables suffers from reusability.

One other aspect of a global variable is that it is available only from the point of declaration to the end of the program. Consider a program segment as shown below:

main()
{
y = 5;
….
….
}
int y; /* global declaration */
func1()
{
y = y+1;
}

We have a problem here. As far as main is concerned, y is not defined. So, the compiler will issue an error message. Unlike local variables, global variables are initialized to zero by default. The statement y = y+1; in fun1 will, therefore, assign 1 to y.

External Declaration

In the program segment above, the main cannot access the variable y as it has been declared after the main function. This problem can be solved by declaring the variable with the storage class extern.

For Example :
main()
{
extern int y; /* external declaration */
…..
…..
}
func1()
{
extern int y; /* external declaration */
…..
…..
}
int y;    /* definition */

Although the variable y has been defined after both the functions, the external declaration of y inside the functions informs the compiler that y is an integer type defined somewhere else in the program.

Note that extern declaration does not allocate storage space for variables. In case of arrays, the definition should include their size as well.

The distinction between definition and declaration also applies to functions. A function is defined when its parameters and function body are specified.

This tells the compiler to allocate space for the function code and provides type information for the parameters.

Since functions are external by default, we declare them (in the calling functions) without the qualifier extern.

Therefore, the declaration void print out (void); is equivalent to extern void print out (void); Function declarations outside of any function behave the same way as variable declarations.

Static Variables in C

As the name suggests, the value of static variables persists until the end of the program. A variable can be declared static using the keyword static like
static int x;
static float y;
A static variable may be either an internal type or an external type depending on the place of declaration.

Internal static variables are those which are declared inside a function. The scope of internal static variables extend up to the end of the function in which they are defined.

Therefore, internal static variables are similar to auto variables, except that they remain in existence (alive) throughout the remainder of the program.

Therefore, internal static variables can be used to retain values between function calls. For example, it can be used to count the number of calls made to a function.

Program
     void stat(void);
     main()
     {
        int i;
        for(i=1; i<=3; i++)
        stat();
     }
     void stat(void)
     {
        static int x = 0;

        x = x+1;
        printf("x = %d\n", x);
    }
Output
     x = 1
     x = 2
     x = 3

A static variable is initialized only once, when the program is compiled. It is never initialized again. During the first call to stat, X is incremented to 1.

Because x is static, this value persists and therefore, the next call adds another 1 to x giving it a value of 2. The value of x becomes three when the third call is made.

Had we declared x as an auto variable, the output would have been:
X=1
X=1
X=1
This is because each time stat is called, the auto variable x is initialized to zero. When the function terminates, its value of 1 is lost.

An external static variable is declared outside of all functions and is available to all the functions in that program.

The difference between a static external variable and a simple external variable is that the static external variable is available only within the file where it is defined while the simple external variable can be accessed by other files.

It is also possible to control the scope of a function. For example, we would like a particular function accessible only to the functions in the file in which it is defined, and not to any function in other files.

This can be accomplished by defining ‘that’ function with the storage class static.

Register Variables

We can tell the compiler that a variable should be kept in one of the machine’s registers, instead of keeping in the memory (where normal variables are stored).

Since a register access is much faster than a memory access, keeping the frequently accessed variables (loop control variables) in the register will lead to faster execution of programs.

This is done as follows: register int count; Although, ANSI standard does not restrict its application to any particular data type, most compilers allow only int or char variables to be placed in the register.

Since only a few variables can be placed in the register, it is important to carefully select the variables for this purpose.

However, C will automatically convert register variables into non-register variables once the limit is reached. Table summarizes the information on the visibility and lifetime of variables in functions and files.

Nested Blocks

A set of statements enclosed in a set of braces is known a block or a compound statement. Note that all functions including the main use compound statement.

A block can have its own declarations and other statements. It is also possible to have a block of block, thus creating what is known as nested blocks.

main()
{
int a = 20;
int b = 10;
…..
{
int a = 0;
int c = a + b;
…..
}
b = a;
}

When this program is executed, the value C will be 10, not 30. The statement b = a; assigns a value of 20 to b and not zero. Although the scope of a extends up to the end of main it is not “visible” inside the inner block where the variable a has been declared again.

The inner a hides the visibility of the outer a in the inner block. However, when we leave the inner block, the inner a is no longer in scope and the outer a becomes visible again.

Remember, the variable b is not re-declared in the inner block and therefore it is visible in both the blocks.

That is why when the statement int c = a + b; is evaluated, a assumes a values of 0 and b assumes a value of 10. Although main’s variables are visible inside the nested block, the reverse is not true.

Scope Rules

Scope
The region of a program in which a variable is available for use.
Visibility
The program’s ability to access a variable from the memory.
Lifetime
The lifetime of a variable is the duration of time in which a variable exists in the memory during execution.

Rules of Use

  1. The scope of a global variable is the entire program file.
  2. The scope of a local variables c begins at point of declaration and ends at the end of the block or function in which it is declared.
  3. The scope of a formal function argument is its own function.
  4. The lifetime (or longevity) of an auto variables in c declared in main is the entire program execution time, although its scope is only the main function.
  5. The life of an auto variable declared in a function ends when the function is exited.
  6. A static local variable, although its scope is limited to its function, its lifetime extends till the end of program execution.
  7. All variables have visibility in their scope, provided they are not declared again.
  8. If a variable is redeclared within its scope again, it loses its visibility in the scope of the redeclared variables in c.
Read More Topics
Const member function in C++
Static data members in C++
Inline function in C++
Recursion in C++

About the author

Santhakumar Raja

Hi, This blog is dedicated to students to stay update in the education industry. Motivates students to become better readers and writers.

View all posts

Leave a Reply