Null Statement in C
In this lesson we explore the concept of null statement in C language.
We analyze how and when to use this statement, highlighting both the situations in which it can simplify the code and the typical errors that can be made.
Null Statement
In C language a statement can also be empty or null.
In practice, it is a statement without any operation, which executes nothing. To introduce a null statement, simply use a semicolon (;).
For example:
int x = 5;
int y = 10;
x += 3;
; // Null statement
y -= 2;
In this example, the null statement (;) has no effect on the program.
Null Statement
A Null Statement in C is a statement that executes no operation, represented by a semicolon:
;
Uses of Null Statement
At this point the question arises: why use a null statement?
This type of statement is mainly used to create loops whose bodies are empty, in the sense that they do not need to execute any operation inside the loop itself.
Let's see an example. Suppose we want to create a program that verifies whether an integer number entered by the user is a prime number or not.
To implement this program we can use a primality test that checks if the number is divisible by other numbers. In particular, we can check if the number is divisible by all numbers between 2 and itself minus 1.
A first way to implement this test in C could be the following:
#include <stdio.h>
int main() {
printf("Enter an integer number: ");
int number;
scanf("%d", &number);
int d;
for (d = 2; d < number; d++)
if (number % d == 0)
break; // If the number is divisible, exit from the loop
if (d == number) {
printf("%d is a prime number.\n", number);
} else {
printf("%d is not a prime number.\n", number);
}
return 0;
}
In this first implementation, the heart of the algorithm is the for loop:
for (d = 2; d < number; d++)
if (number % d == 0)
break; // If the number is divisible, exit from the loop
This loop iterates over all numbers from 2 to number - 1, checking if the entered number is divisible by each of them. If it finds a divisor, it exits from the loop with the break statement.
However, we can modify the loop so that it does not execute any operation inside its body, using a null statement.
First, we move the if condition inside the for loop declaration, so as to check the divisibility directly during the iteration. Then, we can use a null statement for the loop body:
for (d = 2; d < number && number % d != 0; d++)
; // Null statement
In this way, at each iteration of the loop, the condition d < number is first checked. If this condition is false, since the && operator works in short circuit, the second condition number % d != 0 is not evaluated, and the loop terminates.
If instead the condition is true, the divisibility of the number is checked, and if this is false, the loop continues without executing any operation thanks to the null statement.
At the end of the loop, one of the two conditions will be false: either d will be equal to number, or number % d will be equal to 0, indicating that the number is not prime.
Insert a null statement on a separate line
Let's make a small observation about the code of the previous example.
We inserted the null statement on a separate line by itself:
for (d = 2; d < number && number % d != 0; d++)
; // Null statement
We could have written the null statement on the same line as the for loop, as follows:
for (d = 2; d < number && number % d != 0; d++) ;
However, this practice is highly discouraged, as it makes the code less readable and can confuse those who read it.
For example, taking the previous code, if we wrote:
for (d = 2; d < number && number % d != 0; d++) ;
if (d == number) {
printf("%d is a prime number.\n", number);
} else {
printf("%d is not a prime number.\n", number);
}
At first glance, it might seem that the if statement is part of the for loop, which is not correct. In reality, the if statement is executed once after the for loop has terminated.
Therefore, our advice is to always insert the null statement on a separate line.
A final observation concerns the fact that transforming a loop with a body into a loop with a null statement does not necessarily make the code more efficient. It is a matter of style and code readability, rather than performance. However, there are cases in which the use of a null statement can simplify the program logic and make it clearer, as we will see when we study strings.
Null Statement and Programming Errors
The use of the null statement can lead to programming errors if not used correctly, often resulting in enormous confusion for developers.
In this section we see what the most common ones are.
-
Inserting a null statement at the end of an
ifstatement:Let's take the following example:
if (x > 0); /* ERROR */ printf("x is positive.\n");In this case we inserted a semicolon (
;) at the end of theifstatement, i.e., a null statement. This means that theprintfstatement is not part of theifblock, but is always executed, regardless of the value ofx. The result will be that the message will be printed even whenxis not positive. -
Accidental creation of an infinite loop with
while:Let's consider the following code:
int i = 0; while (i < 10); /* ERROR */ i++;Here we have a
whileloop that seems correct, but the null statement at the end of the loop (i.e., the semicolon placed after thewhile) means that the loop body is empty. Consequently,iis never incremented and the loop becomes infinite, blocking the program execution. -
Executing the body of a loop only once:
Another common error is to insert a semicolon after a
fororwhilestatement. The consequence is that the loop body is executed only once. For example:for (int i = 0; i < 5; i++); /* ERROR */ printf("i: %d\n", i);In this case, the null statement at the end of the
forloop means that although the variableiis incremented, theprintffunction, which should be the real body of the loop, is executed only once after the loop has terminated. This can lead to unexpected results.
Based on these examples, it is clear that the use of the null statement requires attention and caution. It is important to be aware of how and where it is used to avoid logical errors in the code.