Lexical Structure
Statements & Blocks
A statement is one instruction ending with a semicolon ; — the period of the C language. A block is zero or more statements wrapped in curly braces { }. Blocks group statements so that if, loops, and functions can execute several instructions as one unit, and they create a new scope for local names.
int main(void) { // { opens the function block
int a = 1; // declaration statement
int b = 2; // another declaration
a = a + b; // assignment statement (expression + ;)
return a; // return statement
} // } closes the block
C is a free-form language: spaces, tabs, and newlines are insignificant outside string literals and comments. Use indentation only for the reader — the compiler does not care. Semicolons are mandatory; forgetting one is the most common beginner compile error.
Declarations Introduce Names
Every name must be declared with a type before use — that is how the compiler knows how many bytes it occupies and what the operators may do with it. A declaration can also initialize the variable in the same statement:
int score = 100; // declares int 'score', initial value 100
double pi = 3.14159; // declares double 'pi' with an approximate value
char letter = 'A'; // one character, quoted with single quotes
int count; // declared but NOT initialized — contains garbage
Comments
Two comment forms exist. Use // for a line note (standard since C99) and /* ... */ for multi-line or block notes, which can also disable code temporarily.
// single-line comment: everything to the end of the line is ignored
/* block comment:
can span several lines and is
often used for file headers */
int x = 1; /* comments may sit inside a line */ int y = 2;
Comments cannot be nested in standard C — a /* inside a /* ... */ block ends the block at the first */. Keep comments about why, never about what; the code already says what.
Identifiers & Keywords
An identifier names a variable, function, type, or label. It must start with a letter or underscore and continue with letters, digits, or underscores; it is case-sensitive (Score and score differ). Avoid leading underscores — names starting with _ are reserved for the implementation.
A keyword is a reserved word you cannot use as an identifier. The C11 reserved set, grouped by purpose:
| Group | Keywords |
|---|---|
| Control flow | if else while do for switch case default break continue goto |
| Types | int char float double void short long signed unsigned struct union enum _Bool _Complex |
| Storage & qualifiers | static extern auto register const volatile restrict inline _Thread_local |
| Misc | return sizeof typedef _Alignas _Alignof _Static_assert _Atomic _Generic _Noreturn |
Operators & Expressions
Operators combine operands into expressions. Everything below evaluates to a value of some type; the type rules matter more in C than anywhere else, and the types page explains those rules. The main families:
| Family | Operators | Example |
|---|---|---|
| Arithmetic | + - * / % | total / count |
| Assignment | = += -= *= /= %= | sum += item; |
| Comparison | == != < > <= >= | score >= 60 |
| Logical | && || ! | a > 0 && b > 0 |
| Bitwise | & | ^ ~ << >> | flags & 0xFF |
| Address | & * sizeof | &x, *p |
| Other | ?: ++ -- , -> . | i++, p->field |
Precedence decides grouping when operators compete: the classic pitfall is flags & mask == mask parsing as flags & (mask == mask). When in doubt, add parentheses — clarity beats cleverness, and compilers optimize both identically.
A Small Complete Program
Here is the lexical toolkit assembled into one program: declaration, arithmetic, a comment, a loop, and a condition — all forms you will use in every exercise that follows.
#include <stdio.h> // printf() declaration
int main(void) {
// sum the first five integers with a for loop
int sum = 0; // accumulator, initialized to zero
for (int i = 1; i <= 5; i++) { // declare, test, increment
sum += i; // compound assignment: sum = sum + i
}
// decision: report the parity of the result
if (sum % 2 == 0) {
printf("sum %d is even\n", sum);
} else {
printf("sum %d is odd\n", sum);
}
return 0; // success exit status
}
Next: the data types that give those operators their meaning.