Previous: 3.2.1 Passing Data to and from Functions
Up: 3.2 Defining Functions
Previous Page: 3.2.1 Passing Data to and from Functions
Next Page: 3.3 Coding Programs for Readability
This section reviews and formalizes several features of variables that we have already encountered. We know that direct access of objects is performed by using variable names in expressions. The use of a variable on the left side of an assignment operator stores a new value in that object; the use of a variable anywhere else retrieves the value of the object. Objects defined in one function are not directly accessible to other functions. A calling function passes values of arguments to a called function. Only the values of these arguments, and NOT the arguments themselves, are available to the called function. The values of the arguments are stored in the parameters, and only the called function has access to these parameters. When called functions have access only to argument values, and not to arguments themselves, the function calls are termed call by value. In C, all function calls are call by value. It is impossible for a called function to have direct access to an object defined in the calling function. Let us examine the implications. Consider a program that uses a function to increment the value of an argument.
/* File: incr.c Program Trace
Program demonstrates call by value. x
*/
#include <stdio.h>
main()
{ int x; ??
int incr(int n);
printf("***Call by Value***\n");
x = 7; 7
printf("Original value of x is %d\n", x); 7
printf("Value of incr(x) is %d\n", incr(x)); 7
printf("The value of x is %d\n", x); 7
}
/* Function increments n */ n
int incr(int n) 7
{
n = n + 1; 8
return n; 8
}
Compiling and executing this programs gives the following sample session:
We see that a called function cannot directly change the value of an object defined in the calling function. This is true even if the formal parameter in incr() were called x. Formal parameters represent new and distinct objects unrelated to any other objects defined elsewhere.
The variables declared at the beginning of a block (e.g. a function body) have all been of a storage class called automatic. This means that these variables are automatically created and destroyed each time the function is executed. When the execution of a function begins, the variables declared at the beginning of the function block as well as the formal parameters are created, i.e. memory cells for these variable names are allocated. When the execution of a function is completed (e.g. when a return statement is executed), the memory allocated for these variables is freed, i.e. these variables and their values no longer exist.
Automatic variables can be defined at the beginning of any block within the primary function block and exist only in the block in which they are defined. Memory for automatic variables declared in a block is allocated when the block is entered, and freed when the block is exited.
The scope of a variable is that part of the program where the variable is visible, i.e. where the variable can be accessed directly by name. The scope of automatic variables is local to the block in which they are defined as well as any blocks nested within it. Automatic variables are frequently referred to as local variables, since their scope is local.
A variable of automatic storage class can be explicitly defined in a declaration by preceding it with the keyword auto. Thus, the following declarations declare automatic variables:
auto int x, y;
auto float r;
If no storage class is specified in a declaration,
automatic storage class is assumed by default.
In all of our programs, so far, declarations have been for automatic
variables by default. In general, most variables used in programs are
automatic, and the default declaration without the keyword auto is a
standard practice. Other storage classes will be discussed in
Chapter As we stated before, a declaration only allocates a memory cell and associates the name with the cell; the value in that cell is, in general, unknown. However, it is possible to specify initial values of automatic variables in the declaration statements. Examples include:
int x = 5 * 2;
int y = isquare(2 * x);
float z = 2.8;
The first declaration initializes x to 10,
and the second initializes y to the
value returned by the function call isquare(2 * x).
If the function isquare()
returns the square of its argument, then y in this case,
is initialized to 400, i.e. the
square of 2 * x. Finally, the last declaration initializes the variable z
to the value 2.8.
The syntax for a declaration statement with initialization is:
Consider the following example in which automatic variables are declared in nested blocks:
/* File: auto.c
Program shows declarations of automatic variables in nested
blocks. Scope of automatic variables is the block in which they
are defined.
*/
main()
{ /* outer block */
auto int x = 10, z = 15; /* x and z are allocated and initialized */
printf("***Automatic Variables and Scope***\n\n");
{ /* inner block */
int x = 20, y = 30; /* new variables x and y are allocated */
/* only the new x can be accessed */
printf("In the inner block: \n");
printf("x = %d, y = %d, z = %d\n",
x, y, z); /* new x and y, and z are printed */
} /* new x and y are freed */
printf("In the outer block:\n");
printf("x = %d, z = %d\n", x, z); /* only the old x can be */
/* accessed in the outer block.*/
/* printf("y = %d\n", y); error: y is not visible here. */
}
The program contains an outer block, which is the function
body for main(), and an inner block.
The scope rules say that an inner block can access variables
declared within it plus any variables declared in an enclosing block.
However, if the
same variable name is used in an inner and an outer block, the local variable
in the inner block is accessed. The outer block cannot access variables defined
in an inner block.
In the example, variables x and z
are declared in the outer block and assigned
values. The outer block can access only these variables.
Variables x and y are
declared in the inner block and assigned values. The inner block can access the
variables z, y, and that x
which is defined in the inner block. As shown in a
comment, if the outer block tried to access y, a compile time error would
occur.
This behavior can be seen in Figure 3.8.
The allocation of storage is shown when the program is executing within the inner block as can be seen by the nested box containing x and y. When this block is completed, the inner box, and all variables inside, is freed. A sample output of the program shows the results:
It is also possible to qualify an automatic variable as a constant using the keyword const. A const qualifier allows initialization of a variable but the variable may not be otherwise changed within the program. Here is an example:
const int x = 100;In the above case, x is initialized to 100 and qualified as a constant. Its value may not be changed elsewhere in the program, e.g. in an assignment statement. Constant qualifiers are used to ensure that certain variable values are not altered by oversight.
Let us consider a somewhat more meaningful example that declares a variable in an inner block. The task is to swap values of two objects, x and y. We need a temporary variable to save one of the values; otherwise, assigning the value of to x would overwrite the original value of x. We can declare the temporary value in an inner block.
/* File: swap.c
This program swaps values of two objects. It defines and uses a
temporary variable in an inner block.
*/
#include <stdio.h>
main()
{ int x = 10, y = 20;
printf("***Swap Values***\n\n");
printf("Original values: x = %d, y = %d\n", x, y);
{ int temp;
temp = x;
x = y;
y = temp;
}
printf("Swapped Values: x = %d, y = %d\n", x, y);
}
Here is the output of the program:
Defining variables in blocks other than a primary function block is not recommended unless there are good reasons for it. In the above example, a temporary variable is declared closest to its use and has no logical role in the rest of the program. When a function uses many variables, declaring variables closest to their use may make it easier to understand the program behavior. For the most part, we will declare all variables at the beginning of primary function blocks.
The formal parameters of a function are also variables that are automatically allocated during a function call, and into which the argument values are passed. Their values, just like those of any other variables, may be changed in the function. The scope of the formal parameters is the body of the function, i.e. the scope is local to the function body.