A statement specifies an action. Except as described below, statements run in order (C17 6.8). A controlling expression is any expression of scalar type: 0 means false, and any other value means true.
Kinds of statement
statement:
labeled-statement
compound-statement
expression-statement
selection-statement if switch
iteration-statement while do for
jump-statement goto continue break return
Labelled statements
labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
A label names a statement as the target of goto, in its own
name space. case
and default labels may appear only inside a switch.
Before C23 a label had to be followed by a statement, which meant a declaration could not come next and a label could not be last in a block. C23 removes both restrictions.
Compound statements
compound-statement:
{ {declaration | statement} }
A pair of braces is a block, and makes a new scope (C17 6.8.2). Since C99, declarations may be mixed with statements. In C89 they had to come before the statements in each block.
{
int a = 1;
printf("%d\n", a);
int b = a + 1; /* allowed since C99 */
printf("%d\n", b);
}
Expression and null statements
An expression followed by ; is evaluated for its side effects, and its value
is discarded (C17 6.8.3). A lone ; is the null statement, which does
nothing. It is useful as the body of a loop, or before a closing brace in older C.
x = 1; /* an expression statement */
f();
while (*s++ != '\0') /* the null statement is the body */
;
if
selection-statement:
if ( expression ) statement
if ( expression ) statement else statement
An else belongs to the nearest preceding if that does not already
have one (C17 6.8.4.1). This is the rule that resolves the
dangling else. Indentation has no effect:
if (a)
if (b)
f();
else /* belongs to if (b), despite the indentation */
g();
switch
selection-statement:
switch ( expression ) statement
The controlling expression must have integer type and undergoes the integer promotions
(C17 6.8.4.2). Control jumps to the matching case, or to default,
or past the whole statement if neither matches. Each case value must be an
integer constant expression, and no two may be equal after conversion to the promoted type.
Control falls through from one label to the next unless something stops it. break
leaves the switch. C23 adds [[fallthrough]]; to mark intended
fall-through.
switch (c) {
case 'a':
case 'e':
vowels++;
break;
case ' ':
spaces++;
[[fallthrough]]; /* C23 */
default:
other++;
break;
}
- A
switchmay not jump into the scope of a variably modified identifier. - Jumping past a declaration with an initialiser is allowed, but the variable is not initialised.
- A label before a declaration is an error before C23. Use a null statement or a nested block.
Iteration statements
iteration-statement:
while ( expression ) statement
do statement while ( expression ) ;
for ( [expression] ; [expression] ; [expression] ) statement
for ( declaration [expression] ; [expression] ) statement
| Statement | Tests |
|---|---|
while | Before each pass; the body may run zero times |
do | After each pass; the body runs at least once |
for | Before each pass, as while does |
In for (init; cond; step), init is evaluated once before the
first test, and step after each pass (C17 6.8.5.3). All three may be omitted,
and a missing condition counts as a non-zero constant. Since C99 init may be a
declaration, and its scope is the rest of the for statement.
A loop whose controlling expression is not a constant may be assumed by the compiler to
terminate if its body has no input, output, volatile access, synchronisation or
atomic operations (C17 6.8.5). So an empty loop waiting on a non-volatile
variable may be removed.
for (int i = 0; i < 10; i++)
total += i;
for (;;) { /* a loop with no exit condition */
if (done()) break;
}
for statementJump statements
| Statement | Effect | Clause |
|---|---|---|
goto label; | Jumps to a label in the same function | 6.8.6.1 |
continue; | Jumps to the end of the innermost loop’s body | 6.8.6.2 |
break; | Leaves the innermost loop or switch | 6.8.6.3 |
return [expression]; | Ends the function | 6.8.6.4 |
gotomay not jump from outside the scope of a variably modified identifier into its scope.returnwith an expression is converted to the function’s return type as if by assignment. A function returningvoidmay not use one, and since C99 a function with a return value must use one.breakleaves only one level. To leave nested loops, use agotoor a flag.
int load(const char *path)
{
int result = -1;
FILE *f = fopen(path, "rb");
if (!f) goto done;
char *buf = malloc(4096);
if (!buf) goto close_file;
/* ... use buf ... */
result = 0;
free(buf);
close_file:
fclose(f);
done:
return result;
}
goto is a common way to write cleanup in one place