Scopes of Identifier in the C Computer Language
Part 34 of the Complete C Course
Foreword: Scopes of Identifier in the C Computer Language
By: Chrysanthus Date Published: 22 Jun 2024
Introduction
Block Scope
Long statements are the if, while, do, for, and switch statements. Each of these statements can have a block. Consider the following program:
int main(int argc, char *argv[])
{
if (1 == 1) {
/*some statements*/
int inte = 25;
/*some statements*/
printf("%i\n", inte);
}
//printf("%i\n", inte);
return 0;
}
The output is 25. The integer, inte can be seen from its point of declaration, to the end of the if-block. The output of 25 was printed by the printf() function call, inside the if-block. That is block scope. inte cannot be seen outside the if-block. If the commenting double forward slash in front of the printf statement below the if-block is taken off, an error message will be outputted at compile time, and the program will not compile. When a program is not compiled into the executable form, it cannot run (cannot be executed). The reader should test the program, with and without the double forward slash of the outer printf statement.
Block Scope and for-loop
Consider the following for-loop:
for (int i=0; i<5; i++) {
/*some statements*/
printf("%i ", i);
/*some statements*/
}
printf("\n");
The for-loop statement begins with the reserved word "for", followed by parentheses and the block delimited by curly brackets. The important information is this: the scope of the variable, i begins from the point of declaration in the parentheses, at "int i=0" , and ends at the end of the block. In other words, the variable, i can be seen in the parentheses, from its point of declaration, to the end of the parentheses, and continue to be seen anywhere inside the block {}. Note, it cannot be seen outside the block.
Nested Blocks
#include <stdio.h>
int main(int argc, char *argv[])
{
/* A statements*/
if (1 == 1) {
/* B statements*/
if (2 == 2) {
/* C statements*/
}
/* B statements*/
}
/* A statements*/
return 0;
}
There is the block of the C main() function; there is the nested if-block beginning with (1 == 1) in the block of the main() function; and there is the innermost nested if-block beginning with if (2 == 2), in the block of the outrer if-block beginning with (1 == 1).
The important information is this: a variable declared inside a block, cannot be seen outside the block. This means that a variable declared inside a nested block, cannot be seen outside, and in its nesting block. Also, the scope of the nesting block, is before the nested block and after the nested block. Look at where the A statements are, where the B statements are, and where the C statements are, in the above program.
Another important information is this: A variable declared in a block, is seen inside a nested block and inside a nested nested block, and in all inner nested blocks. The following program illustrates this:
#include <stdio.h>
int main(int argc, char *argv[])
{
int inte = 5;
if (1 == 1) {
printf("%i\n", inte);
if (2 == 2) {
printf("%i\n", inte);
}
}
printf("%i\n", inte);
return 0;
}
The output is 5, 5, 5 in three separate lines.
Overriding in Nested Block
#include <stdio.h>
int main(int argc, char *argv[])
{
int inte = 5;
if (1 == 1) {
int inte = 6;
printf("%i\n", inte);
if (2 == 2) {
printf("%i\n", inte);
}
}
printf("%i\n", inte);
return 0;
}
The integer inte, is declared outside the block beginning with (1 == 1) as "int inte = 5;". It is re-declared inside the block to have a different value as, "int inte = 6;". Actually, this is not re-declaration. It is two declarations in two different scopes with the same name (identifier). And so the output is 6, 6, 5 in three different lines. And so the variable has been overridden completely inside the nested block.
Of course the overriding can be with a different type, as in the following program:
#include <stdio.h>
int main(int argc, char *argv[])
{
int inte = 5;
if (1 == 1) {
float inte = 6.6;
printf("%f\n", inte);
if (2 == 2) {
printf("%f\n", inte);
}
}
printf("%i\n", inte);
return 0;
}
The output is 6.600000, 6.600000, 5, with each value on a separate line.
Function Scope
#include <stdio.h>
int fun (int a, int b, int c) {
printf("%i\n", a);
printf("%i\n", b);
int d = 3;
printf("%i\n", d);
return c;
}
int main(int argc, char *argv[])
{
int myInt = fun(1, 2, 4);
printf("%i\n", myInt);
return 0;
}
The output is 1, 2, 3, 4, with each value on a separate line. The signature of the function is,
int fun (int a, int b, int c)
The function call is: "fun(1, 2, 3)". When the function is called, the value of a becomes 1, and a is seen from its point of declaration in the parentheses, to the end of the parentheses, ), and is seen all over in the function block. b is seen from its point of declaration in the parentheses, to the end of the parentheses, and is seen all over in the function block. c is seen from its point of declaration in the parentheses, to the end of the parentheses, and is seen all over in the function block. a, b, and c are in the function scope of the function, fun(). A scope is a region of text, where a variable is seen.
The variable, d is in the block scope of the function, fun(), as well as it is in the function scope of the same function; though d is not seen in the parentheses. The function scope begins from within the parentheses to the end of its block.
Function Prototype Scope
#include <stdio.h>
int fun (int a, int b, int c);
int fun (int a, int b, int c) {
printf("%i\n", a);
printf("%i\n", b);
int d = 3;
printf("%i\n", d);
return c;
}
int main(int argc, char *argv[])
{
int myInt = fun(1, 2, 4);
printf("%i\n", myInt);
return 0;
}
This program is the same as the previous program, except that the function, fun() has the prototype, "int fun (int a, int b, int c);" separately. The function signature is always attached to the function body in the function definition. The output is the same as for the previous program.
In the prototype, the scope of the each of the variables, begin from its point of declaration, to the end of the right brackets, ). It does not, in theory, continue into the block of the function, since the block of the function is detached from the prototype. That is function prototype scope.
The label name (identifier) has function scope. The following program illustrates this with the C main() function:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%c ", 'A');
goto labl1;
printf("%c ", 'B');
labl1:
printf("%c ", 'C');
goto labl2;
printf("%c ", 'D');
labl2:
printf("\n");
return 0;
}
The output is A C.
File Scope
If an identifier (variable) is said to have a file scope, it means that the identifier can be seen everywhere in the file. The following program illustrates this:
#include <stdio.h>
int inte = 5;
void fn() {
printf("%i\n", inte);
}
int main(int argc, char *argv[])
{
fn();
if (1 == 1) {
printf("%i\n", inte);
if (2 == 2) {
printf("%i\n", inte);
}
}
printf("%i\n", inte);
return 0;
}
The output is 5, 5, 5, 5 with each value on a separate line. For an identifier to be appreciated as being in the file scope, it has to be declared around the top of the program. It does not have to be declared inside any block. The scope of a file scope identifier, ends at the end of the program. That is, a file scope terminates at the end of the file (end of the translation unit).
Issue of Initialization in File Scope, outside Function Body
In the file scope, a declaration can occur with initialization, in one statement. Read and test the following program:
#include <stdio.h>
int myInt = 5;
int main(int argc, char *argv[])
{
printf("%i\n", myInt);
return 0;
}
The program works; the output is 5; declaration and initialization, occurred in one statement in the file scope. Now, read and test the following program, where the declaration and initialization have been separated into two statements, in the file scope:
#include <stdio.h>
int myInt;
myInt = 5;
int main(int argc, char *argv[])
{
printf("%i\n", myInt);
return 0;
}
Compilation stopped; and an error message was issued. This is because, declaration and initialization, in two different statements, is not allowed in file scope. However, the initialization can be done in the function scope, even if it is the C main() function. Read and test the following code:
#include <stdio.h>
int myInt;
int main(int argc, char *argv[])
{
myInt = 5;
printf("%i\n", myInt);
return 0;
}
Compilation completes; the program works; the output is 5.