Most statements in C++ end with a semicolon. An expression, such as ival + 5
, becomes an expression statement when it is followed by a semicolon. Expression statements cause the expression to be evaluated and its result discarded:
ival + 5; // rather useless expression statement
cout << ival; // useful expression statement
The first statement is pretty useless: The addition is done but the result is not used. More commonly, an expression statement contains an expression that has a side effect—such as assigning a new value to a variable, or printing a result—when it is evaluated.
The simplest statement is the empty statement, also known as a null statement. A null statement is a single semicolon:
; // null statement
A null statement is useful where the language requires a statement but the program’s logic does not. Such usage is most common when a loop’s work can be done within its condition. For example, we might want to read an input stream, ignoring everything we read until we encounter a particular value:
// read until we hit end-of-file or find an input equal to sought
while (cin >> s && s != sought)
; // null statement
This condition reads a value from the standard input and implicitly tests cin
to see whether the read was successful. Assuming the read succeeded, the second part of the condition tests whether the value we read is equal to the value in sought
. If we found the value we want, the while
loop is exited. Otherwise, the condition is evaluated again, which reads another value from cin
.
Null statements should be commented. That way anyone reading the code can see that the statement was omitted intentionally.
Because a null statement is a statement, it is legal anywhere a statement is expected. For this reason, semicolons that might appear illegal are often nothing more than null statements. The following fragment contains two statements—the expression statement and the null statement:
ival = v1 + v2;; // ok: second semicolon is a superfluous null statement
Although an unnecessary null statement is often harmless, an extra semicolon following the condition in a while
or if
can drastically alter the programmer’s intent. For example, the following code will loop indefinitely:
// disaster: extra semicolon: loop body is this null statement
while (iter != svec.end()) ; // the while body is the empty statement
++iter; // increment is not part of the loop
Contrary to the indentation, the increment is not part of the loop. The loop body is the null statement formed by the semicolon that follows the condition.
A compound statement, usually referred to as a block, is a (possibly empty) sequence of statements and declarations surrounded by a pair of curly braces. A block is a scope (§ 2.2.4, p. 48). Names introduced inside a block are accessible only in that block and in blocks nested inside that block. Names are visible from where they are defined until the end of the (immediately) enclosing block.
Compound statements are used when the language requires a single statement but the logic of our program needs more than one. For example, the body of a while
or for
loop must be a single statement, yet we often need to execute more than one statement in the body of a loop. We do so by enclosing the statements in curly braces, thus turning the sequence of statements into a block.
As one example, recall the while
loop in the program in § 1.4.1 (p. 11):
while (val <= 10) {
sum += val; // assigns sum + val to sum
++val; // add 1 to val
}
The logic of our program needed two statements but a while
loop may contain only one statement. By enclosing these statements in curly braces, we made them into a single (compound) statement.
We also can define an empty block by writing a pair of curlies with no statements. An empty block is equivalent to a null statement:
while (cin >> s && s != sought)
{ } // empty block
Exercises Section 5.1
Exercise 5.1: What is a null statement? When might you use a null statement?
Exercise 5.2: What is a block? When might you might use a block?
Exercise 5.3: Use the comma operator (§ 4.10, p. 157) to rewrite the
while
loop from § 1.4.1 (p. 11) so that it no longer requires a block. Explain whether this rewrite improves or diminishes the readability of this code.