Statements and Structure

At the top-level, a C program is nothing more than a series of external object and function definitions–remember, in this context “external” means “top-level”, not linkage! Within each function definition, procedural units of code called statements are used to evaluate expressions, organize the program into blocks, and control program flow.

statement:

expression-statement

labeled-statement

compound-statement

selection-statement

iteration-statement

jump-statement

Expression Statements

An expression statement takes the form,

expression-statement:

[ expression ]

;

An expression statement simply evaluates the provided expression and discards any resulting value.

If expression is omitted, it is also called a null statement, which does nothing.

Labeled Statements

Any statement can be labeled,

label-statement:

label

:

statement

A labeled statement constitutes a declaration of that label; unlike other types of declarations, a label has function-scope, which means it is visible for the entire function it is declared in including any portion of that function body before the label.

There are two special types of labels which can only appear inside a switch statement,

label-statement:

case

constant-expression

:

statement

default

:

statement

Since neither of these forms declares an identifier, the only way that these labels are jumped to is based on the controlling expression of a switch statement, as described below.

Compound Statements

One or more statements may be grouped together into a compound statement,

compound-statement:

{

statement

}

Each compound statement is also called a block and introduces a new block scope that extends to the closing curly brace. Automatic variables declared within a block are scoped to that block, and are destroyed at the end of the block when going out of scope.

Selection Statements

There are two selection statements–the if and switch statements,

selection-statement:

if

(

expression

)

statement

if

(

expression

)

statement

else

statement

switch

(

expression

)

statement

The controlling expression of an if statement is a scalar value; the first substatement is executed if the controlling expression compares unequal to 0. In the else form, the second substatement is executed if the controlling expression evaluates equal to 0.

As the if statement is, itself, a statement, multiple if statements can be chained together, as shown below,

if ( /* condition */) {
/* ... */
} else if ( /* condition */ ) {
/* ... */
} else {
/* ... */
}

The controlling expression of a switch statement is an integer value. In practice, the switch statement subexpression, called the switch body, is a compound statement containing case and/or default labeled statements. The switch statement causes a jump to the first matching case statement, or the default statement, if present. For example,

switch (x) {
case 0:
   /* ... */
   break;
case 1:
   /* ... */
   break;
case -1:
   /* ... */
   break;
default:
   /* ... */
}

Notice the use of break statements to exit the switch body before each new label. These may be omitted, in which case execution falls through into subsequent statements.

Iteration Statements

There are three iteration, or loop, statements in C, the while loop, the do-while loop, and the for loop,

selection-statement:

while

(

expression

)

statement

do

statement

while

(

expression

)

for

(

clause-1

;

expression-2

;

expression-3

)

statement

An iteration statement executes its substatement, called the loop body, repeatedly until the controlling expression compares equal to 0. The while and for loops evaluate this expression before each execution of the loop body, while the do-while loop evaluates it at the end of the loop body.

The for loop exits as a shorthand for a while loop with an iteration variable, and is exactly equivalent to,

{

clause-1

;

while

(

expression-2

)

{

statement

expression-3

;

}

}

In other words, clause-1, which may be a declaration or statement, is executed once before the loop. Typically, this is used to declare iteration variable(s). The controlling expression, expression-2 is evaluated each time before the loop body is executed, as with the while loop. At the end of the loop body, and before evaluating the controlling expression, expression-3 is evaluated. A typical usage pattern to iterate over an array of known size would be,

for (int i = 0; i < array_size; ++i) {
  array[i] += 1;
}

Similarly, for loops are frequently used with pointers rather than indices, such as when working with null-terminated strings,

/* Convert a string to uppercase */
char *str_toupper(char *s)
{
   for (char *c = s; *c; ++c) {
      *c = toupper(*c);
   }
   return s;
}

Any of clause-1, expression-2, and expression-3 may be omitted from a for loop. If expression-2 is omitted, then it is replaced with a non-zero value–i.e. an unconditional loop. The traditional convention is to use for loops with no controlling expression to denote unconditional loops in C,

for (;;) {
  /* Loop forever */
}

Jump statements

Jump statements are used to unconditionally jump to a labeled statement,

jump-statement:

goto

label

;

immediately jump to the end of a loop body to execute another iteration,

jump-statement:

continue

;

break out of a loop or switch statement body,

jump-statement:

break

;

or return from a function,

jump-statement:

return

[ expression ]

;