The parts of a C++ program are a small, learnable set: preprocessor directives, declarations, statements and blocks, grouped inside functions, with exactly one of those functions named [[main]] acting as the entry point. Once you can name each piece of a file out loud, code stops being a wall of characters and starts being a structure you can navigate.
The layers of a C++ program
A source file is built in layers, from the outside in.
- Preprocessor directives — lines beginning with
#, such as#includeand#define. They are handled before compilation proper and are not really C++ code. - Declarations — introduce names: functions, variables, types, namespaces.
- Statements — the instructions. A statement ends with a semicolon.
- Blocks — groups of statements inside braces, which also create a scope.
The top-level structure of a program is a sequence of declarations and definitions. Function definitions contain blocks of statements. That hierarchy is all a beginner needs to hold in their head.
#include // layer 1: preprocessor directive
double to_fahrenheit(double c) { // layer 2: declaration of a function
return c * 9.0 / 5.0 + 32.0; // layer 4: block containing one statement
}
int main() { // layer 2: the entry point
double celsius = 21.5; // layer 3: a declaration with a statement
std::cout << to_fahrenheit(celsius) << " F\n"; // layer 3: an expression statement
return 0;
}Statements, expressions and the semicolon
A statement is an instruction that does something. The simplest statement is the expression statement: an expression followed by a semicolon. In the line above, to_fahrenheit(celsius) is an expression — something that produces a value — and the whole line is a statement that discards it or prints it.
The semicolon is not decoration. It is the token that tells the compiler "this instruction ends here". Leave it out and the parser keeps consuming the next line looking for the end of the statement, producing a cascade of errors that point at the wrong place.
The main categories of statement you will meet early are expression statements, declarations with an initialiser, if and loop statements, return statements, and switch. Each is a complete instruction with its own syntax rules.
Blocks and scope
A block is a set of statements wrapped in braces. Blocks do two jobs at once: they group statements so they can be used as a unit, and they introduce a scope, meaning the names declared inside are only visible inside.
#include
int main() {
int temperature = 18;
{
int temperature = 25; // shadows the outer variable
std::cout << "inside: " << temperature << '\n';
}
std::cout << "outside: " << temperature << '\n';
return 0;
}The inner value wins inside the block and the outer value is intact afterwards:
inside: 25
outside: 18The inner temperature shadows the outer one for the duration of the inner block. The outer variable is untouched and comes back into view when the block ends. Shadowing is legal and occasionally useful, but it is also a classic source of confusion, so a different name is usually the clearer choice.
Note that the scope rule applies to names, not to values. The inner block did not destroy or modify the outer variable; it simply introduced a different name that happened to look the same.
Names, whitespace and formatting
Identifiers — the names you choose for variables, functions and types — may contain letters, digits and underscores, and may not start with a digit. They are case-sensitive, so count and Count are two different names.
Beyond that, C++ is almost entirely free-form about layout. The compiler does not care where you put spaces, so you can write a whole program on one line. You should not, though, because humans read the code.
#include
int main()
{
int readings = 3;
double average = 21.5;
std::cout << "averaging " << readings << " readings\n";
if (average > 20.0)
{
std::cout << "warm: " << average << '\n';
}
else
{
std::cout << "cool: " << average << '\n';
}
return 0;
}The output confirms that both branches produce exactly one line and that the braces changed nothing about the behaviour:
averaging 3 readings
warm: 21.5Two conventions are worth adopting straight away. Put the opening brace of a function on its own line and the braces of control-flow statements on the same line as the keyword — this is the style used by the C++ Core Guidelines and by most modern codebases. And never skip braces around a single statement, even when the statement is one line: adding an extra line later and forgetting the braces is a bug that the compiler will happily accept.
Comments and what they are for
A comment is ignored by the compiler and exists purely for the reader. C++ gives you three forms.
// Line comment: good for a note attached to one line of code.
/*
Block comment: good for a paragraph of explanation that
should not sit in the middle of a dense piece of logic.
*/
/**
Documentation comment: picked up by documentation tools
to describe a function, its parameters and its result.
*/
int main() {
return 0;
}The rule of thumb: comment the intent, not the mechanics. Writing // increment i above i++; adds nothing. Writing // skip the header row above a line that reads a CSV header does.
Where a program starts and ends
Execution begins at main and nothing runs before it. Code at namespace scope that is not inside a function is either a declaration or a definition; a definition such as a global variable is initialised before main starts, but no other statement executes until main is entered.
That is why global variables with initialisers that call functions are legal but surprising: the initialiser runs before main exists to catch failures. Prefer doing the work inside main and passing results around explicitly.
Quick reference
- A file is preprocessor directives, then declarations and definitions, then statements inside blocks.
- Exactly one function is the entry point:
int main(). - A statement ends with a semicolon; a block is statements wrapped in braces.
- Braces create scope, and inner names shadow outer ones.
- Indentation is for humans, not the compiler — but keep it consistent and always use braces.
- Comments should explain intent; the code already explains the mechanics.
Try it yourself: take the temperature converter from the previous lesson and label every line with a comment saying whether it is a directive, a declaration, a statement or part of a block. Then move the conversion into a named function, and finally convert every single-statement body to braced form and confirm the output is unchanged.