Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

C++  Module 1 – Start here: toolchains, compiling and first programs

C++ program structure, naming and formatting

Lay out a small C++ program in functions and blocks, pick one naming style, format code with clang-format, and see why using namespace std; causes clashes.

  • Beginner
  • 15 minutes
  • Examples run with Clang 21.0.0, GCC 16.2.0 and Python 3.14.8
  • By MySmartCoPilot
Free: 15 minutes

What you will learn

  • Organise a small program into functions and blocks
  • Apply consistent formatting with clang-format
  • Explain why 'using namespace std;' must never appear in a header

Before you start

What you’ll learn · Before you start

What you will learn

  • Organise a small program into functions and blocks
  • Apply consistent formatting with clang-format
  • Explain why 'using namespace std;' must never appear in a header

Before you start

On this page

A C++ program that others can read follows a few conventions: a file runs from its #include lines to main, the work is split into small functions with names that say what they do, every block is indented the same way, and names from std are written as std:: names. None of this changes what the compiler produces, but it decides how quickly you, a teammate or an examiner can find a mistake. This lesson shows the usual layout of a small program, how braces limit where a name exists, how to choose names, how clang-format formats a whole file in one command, and why using namespace std; breaks a program that has a variable called count.

The parts of a small program

This program counts the fours and sixes in an innings, read ball by ball from standard input:

A small program in six parts C++ · boundaries.cpp
// Counts the fours and sixes in an innings, read ball by ball from standard input.
#include <iostream>
#include <print>
#include <vector>

constexpr int four_runs = 4;
constexpr int six_runs = 6;

std::vector<int> read_runs();
int count_boundaries(const std::vector<int>& runs);

int main() {
    const std::vector<int> runs = read_runs();
    std::println("{} balls, {} boundaries", runs.size(), count_boundaries(runs));
}

// Reads whole numbers until the input ends or holds something that is not a number.
std::vector<int> read_runs() {
    std::vector<int> runs;
    int run = 0;
    while (std::cin >> run) {
        runs.push_back(run);
    }
    return runs;
}

int count_boundaries(const std::vector<int>& runs) {
    int boundaries = 0;
    for (int run : runs) {
        if (run == four_runs || run == six_runs) {
            ++boundaries;
        }
    }
    return boundaries;
}
Built with both compilers, given seven balls Python · boundaries_session.py
from session import run

run("""
cat innings.txt
clang++ -std=c++23 -Wall -Wextra -Wpedantic boundaries.cpp -o boundaries && ./boundaries < innings.txt
g++-16 -std=c++23 -Wall -Wextra -Wpedantic boundaries.cpp -o boundaries && ./boundaries < innings.txt
""")

Output

$ cat innings.txt
1 4 0 6
2 4 1
$ clang++ -std=c++23 -Wall -Wextra -Wpedantic boundaries.cpp -o boundaries && ./boundaries < innings.txt
7 balls, 3 boundaries
$ g++-16 -std=c++23 -Wall -Wextra -Wpedantic boundaries.cpp -o boundaries && ./boundaries < innings.txt
7 balls, 3 boundaries

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 boundaries_session.py

With 1 4 0 6 and 2 4 1 as input it printed 7 balls, 3 boundaries. Read from the top, the file has six parts:

The order of a one-file program: a comment, the includes, named constants, declarations, main, then the helper definitions.1. A commentwhat the program does2. #include linesone per header used3. Named constantsconstexpr int four_runs = 4;4. Declarationsof the helper functions5. int main()the outline of the program6. Definitionsof the helper functions

One file, top to bottom

Text description of the diagram

The diagram shows six numbered boxes, in two columns, in the order they appear in the file boundaries.cpp.

  1. A comment that says what the program does.
  2. The #include lines, one for each header the file uses.
  3. Named constants, such as constexpr int four_runs = 4;.
  4. Declarations of the helper functions, so that main can call them before their definitions.
  5. int main(), which reads as an outline of the whole program.
  6. The definitions of the helper functions.
  • A comment on the first line says what the program is for.
  • The #include lines, one per header that the file uses, here sorted alphabetically.
  • Named constants replace bare numbers: four_runs says what 4 means, and constexpr makes it a constant the compiler knows at compile time.
  • Declarations such as int count_boundaries(const std::vector<int>& runs); tell the compiler that a function exists, so main can call it before its definition.
  • main stays short and reads like an outline: read the runs, count the boundaries, print the result.
  • The definitions of the helper functions follow, each doing one job.

Putting the helpers first and main last also works, and then the declarations are not needed. Pick one order for a project and keep it. When a program grows past a few hundred lines, the declarations move into a header file, which the lesson on headers covers.

Blocks and scope

A pair of braces makes a block, and a name declared inside a block exists only until its closing brace. The part of the program where a name can be used is its scope:

A name used after its block has ended C++ · scope.cpp
#include <iostream>

int main() {
    int runs = 7;
    if (runs > 6) {
        int bonus = runs - 6;
        std::cout << "Bonus: " << bonus << '\n';
    }
    std::cout << "Bonus again: " << bonus << '\n';
}
Both compilers stop at line 9 Python · scope_session.py
from session import run

run("""
clang++ -std=c++23 -Wall -Wextra -c scope.cpp -o scope.o
g++-16 -std=c++23 -Wall -Wextra -c scope.cpp -o scope.o
""")

Output

$ clang++ -std=c++23 -Wall -Wextra -c scope.cpp -o scope.o
scope.cpp:9:37: error: use of undeclared identifier 'bonus'
    9 |     std::cout << "Bonus again: " << bonus << '\n';
      |                                     ^~~~~
1 error generated.
[exit status 1]
$ g++-16 -std=c++23 -Wall -Wextra -c scope.cpp -o scope.o
scope.cpp: In function 'int main()':
scope.cpp:9:37: error: 'bonus' was not declared in this scope
    9 |     std::cout << "Bonus again: " << bonus << '\n';
      |                                     ^~~~~
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 scope_session.py

bonus is declared inside the if block, so on line 9, after the closing brace, it no longer exists. Clang said use of undeclared identifier 'bonus' and GCC said 'bonus' was not declared in this scope. Declare a name in the smallest block that needs it, and declare it outside the block when code after the block needs it too. Small scopes keep names from being changed by code that has no business with them, and every function body is a block of its own.

Naming: one style, used everywhere

C++ itself does not prescribe a naming style, and well-known style guides disagree:

Style Types Functions Variables Constants
The standard library snake_case (std::string, std::vector) snake_case (push_back) snake_case snake_case
C++ Core Guidelines Prefer underscore_style names (rule NL.10)
Google C++ Style Guide PascalCase PascalCase snake_case kPascalCase
LLVM Coding Standards PascalCase camelCase PascalCase

The Core Guidelines’ rule NL.8, “Use a consistent naming style”, matters more than which style you choose. This track uses the standard library’s style, snake_case for everything, so its own names look like the library names around them. Whatever the style:

  • Name things for what they are: boundaries, not b; read_runs, not func2. Short names such as i are fine for a loop counter that lives for three lines.
  • Name functions for what they do: a verb, such as count_boundaries.
  • Never start a name with an underscore and a capital letter, and never use two underscores in a row. The standard reserves such names for the compiler and the library, and names that start with an underscore are reserved at global scope too.
Case Converter Turn a phrase or an old name into snake_case, camelCase or PascalCase while you rename.

Formatting with clang-format

Formatting by hand is slow and never quite consistent. clang-format rewrites the layout of a file to a chosen style, without touching what the code does. This file was typed with no care at all:

Before: messy.cpp C++ · style/messy.cpp
#include <vector>
#include <iostream>
int Total(const std::vector<int>&v){int t=0;
for(int x:v){ if(x>0)
t+=x;}
  return t;}
int main( ) {
std::vector<int> runs {4,0,6,1,   2};
    std::cout<<"Total: "<<Total(runs)<<'\n';
      return 0;
}
Two preset styles Python · presets_session.py
from session import run

# On macOS, xcrun runs the clang-format of the Xcode Command Line Tools.
run("""
xcrun clang-format --version
xcrun clang-format --style=llvm style/messy.cpp
xcrun clang-format --style=google style/messy.cpp
""")

Output

$ xcrun clang-format --version
Apple clang-format version 21.0.0 (clang-2100.3.34.2)
$ xcrun clang-format --style=llvm style/messy.cpp
#include <iostream>
#include <vector>
int Total(const std::vector<int> &v) {
  int t = 0;
  for (int x : v) {
    if (x > 0)
      t += x;
  }
  return t;
}
int main() {
  std::vector<int> runs{4, 0, 6, 1, 2};
  std::cout << "Total: " << Total(runs) << '\n';
  return 0;
}
$ xcrun clang-format --style=google style/messy.cpp
#include <iostream>
#include <vector>
int Total(const std::vector<int>& v) {
  int t = 0;
  for (int x : v) {
    if (x > 0) t += x;
  }
  return t;
}
int main() {
  std::vector<int> runs{4, 0, 6, 1, 2};
  std::cout << "Total: " << Total(runs) << '\n';
  return 0;
}

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 presets_session.py

clang-format --style=llvm messy.cpp printed the file in LLVM’s style, two-space indentation and 80 columns, with const std::vector<int> &v and the body of the if on its own line. --style=google printed const std::vector<int>& v and kept if (x > 0) t += x; on one line. Both sorted the two #include lines. clang-format is part of the LLVM tools: install it with your compiler’s LLVM package or a package manager. On this track’s Mac it came with the Xcode Command Line Tools, and xcrun clang-format runs it.

A project writes its choice down in a file named .clang-format (or _clang-format) in its top folder. clang-format looks for that file in the folder of each source file and the folders above it, and editors that run clang-format use it too. This is the style of this track’s examples:

The track's formatting rules Code · style/_clang-format
# This track's formatting: LLVM's style with 4-space indentation, 100 columns, & next to the type,
# and a short if on one line when it has no else.
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 100
PointerAlignment: Left
AllowShortIfStatementsOnASingleLine: WithoutElse

BasedOnStyle: LLVM starts from LLVM’s rules and the other lines change four of them. With that file next to messy.cpp, plain clang-format messy.cpp uses it:

After: the track's rules, and two checks Python · track_style_session.py
from session import run

# With no --style, clang-format reads style/_clang-format, next to the file.
run("""
xcrun clang-format style/messy.cpp
xcrun clang-format --dry-run --Werror style/scores.cpp 2>&1 | grep -c "error:"
xcrun clang-format --dry-run --Werror style/scores_solution.cpp && echo "nothing to change"
""")

Output

$ xcrun clang-format style/messy.cpp
#include <iostream>
#include <vector>
int Total(const std::vector<int>& v) {
    int t = 0;
    for (int x : v) {
        if (x > 0) t += x;
    }
    return t;
}
int main() {
    std::vector<int> runs{4, 0, 6, 1, 2};
    std::cout << "Total: " << Total(runs) << '\n';
    return 0;
}
$ xcrun clang-format --dry-run --Werror style/scores.cpp 2>&1 | grep -c "error:"
39
$ xcrun clang-format --dry-run --Werror style/scores_solution.cpp && echo "nothing to change"
nothing to change

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 track_style_session.py

clang-format fixed the layout but not the names: Total, t, v and x say nothing about the data, and no formatter renames them for you. The session’s last two commands are checks: --dry-run --Werror found 39 places to change in the exercise file scores.cpp further down, and nothing in its solution. Three commands cover daily use:

Command What it does
clang-format -i main.cpp Rewrites the file in place
clang-format --dry-run --Werror main.cpp Changes nothing, and fails with one error for each place that is not formatted; useful in CI
clang-format --style=llvm --dump-config > .clang-format Writes a complete style file to start from

Run the formatter before every commit, or let the editor run it on save, so that changes to a file show only real edits, never reformatted lines.

Text Diff Paste a file before and after clang-format to see every line it changed.

using namespace std; and name clashes

using namespace std; makes every name of namespace std usable without std::. Short programs often start with it, and it fails in a way that is hard to predict:

A global named count C++ · count_clash.cpp
#include <iostream>
using namespace std;

int count = 0;

int main() {
    for (int run : {4, 0, 6, 1}) {
        if (run == 4 || run == 6) {
            ++count;
        }
    }
    cout << "Boundaries: " << count << '\n';
}
Ambiguous on both compilers Python · count_session.py
from session import run

run("""
clang++ -std=c++23 -Wall -Wextra -c count_clash.cpp -o count_clash.o
g++-16 -std=c++23 -Wall -Wextra -c count_clash.cpp -o count_clash.o
""")

Output

$ clang++ -std=c++23 -Wall -Wextra -c count_clash.cpp -o count_clash.o
count_clash.cpp:9:15: error: reference to 'count' is ambiguous
    9 |             ++count;
      |               ^
count_clash.cpp:4:5: note: candidate found by name lookup is 'count'
    4 | int count = 0;
      |     ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__algorithm/count.h:86:1: note: candidate found by name lookup is 'std::count'
   86 | count(_InputIterator __first, _InputIterator __last, const _Tp& __value) {
      | ^
count_clash.cpp:12:31: error: reference to 'count' is ambiguous
   12 |     cout << "Boundaries: " << count << '\n';
      |                               ^
count_clash.cpp:4:5: note: candidate found by name lookup is 'count'
    4 | int count = 0;
      |     ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__algorithm/count.h:86:1: note: candidate found by name lookup is 'std::count'
   86 | count(_InputIterator __first, _InputIterator __last, const _Tp& __value) {
      | ^
2 errors generated.
[exit status 1]
$ g++-16 -std=c++23 -Wall -Wextra -c count_clash.cpp -o count_clash.o
count_clash.cpp: In function 'int main()':
count_clash.cpp:9:15: error: reference to 'count' is ambiguous
    9 |             ++count;
      |               ^~~~~
  • there are 2 candidates
In file included from /opt/homebrew/Cellar/gcc/16.2.0/include/c++/16/bits/unicode.h:39,
                 from /opt/homebrew/Cellar/gcc/16.2.0/include/c++/16/format:62,
                 from /opt/homebrew/Cellar/gcc/16.2.0/include/c++/16/ostream:45,
                 from /opt/homebrew/Cellar/gcc/16.2.0/include/c++/16/iostream:43,
                 from count_clash.cpp:1:
    • candidate 1: 'template<class _IIter, class _Tp> constexpr typename std::iterator_traits<_Iterator>::difference_type std::count(_IIter, _IIter, const _Tp&)'
      /opt/homebrew/Cellar/gcc/16.2.0/include/c++/16/bits/stl_algo.h:4046:5:
       4046 |     count(_InputIterator __first, _InputIterator __last, const _Tp& __value)
            |     ^~~~~
    • candidate 2: 'int count'
      count_clash.cpp:4:5:
          4 | int count = 0;
            |     ^~~~~
count_clash.cpp:12:31: error: reference to 'count' is ambiguous
   12 |     cout << "Boundaries: " << count << '\n';
      |                               ^~~~~
  • there are 2 candidates
    • candidate 1: 'template<class _IIter, class _Tp> constexpr typename std::iterator_traits<_Iterator>::difference_type std::count(_IIter, _IIter, const _Tp&)'
      /opt/homebrew/Cellar/gcc/16.2.0/include/c++/16/bits/stl_algo.h:4046:5:
       4046 |     count(_InputIterator __first, _InputIterator __last, const _Tp& __value)
            |     ^~~~~
    • candidate 2: 'int count'
      count_clash.cpp:4:5:
          4 | int count = 0;
            |     ^~~~~
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 count_session.py

Both compilers rejected line 9 with reference to 'count' is ambiguous: the program’s global count and the standard library’s algorithm std::count are both visible, and the compiler cannot choose. This file includes only <iostream>, yet std::count was there anyway, because both libraries’ <iostream> include parts of the algorithms library: Clang’s note pointed into libc++’s __algorithm/count.h, and GCC’s into libstdc++’s stl_algo.h. A program can compile today and break when the next version of a library includes one header more.

There are three fixes, and the first is the rule this track follows:

  • Write std:: names: std::cout, std::vector. It costs five characters and never clashes.
  • Name the few things you use: using std::cout; brings in only that one name.
  • Keep your own names specific: boundary_count would not have clashed even with using namespace std;.
The fix: std:: names and a specific name C++ · count_fixed.cpp
#include <iostream>

int boundary_count = 0;

int main() {
    for (int run : {4, 0, 6, 1}) {
        if (run == 4 || run == 6) {
            ++boundary_count;
        }
    }
    std::cout << "Boundaries: " << boundary_count << '\n';
}
Built and run Python · count_fixed_session.py
from session import run

run("""
clang++ -std=c++23 -Wall -Wextra -Wpedantic count_fixed.cpp -o count_fixed && ./count_fixed
g++-16 -std=c++23 -Wall -Wextra -Wpedantic count_fixed.cpp -o count_fixed && ./count_fixed
""")

Output

$ clang++ -std=c++23 -Wall -Wextra -Wpedantic count_fixed.cpp -o count_fixed && ./count_fixed
Boundaries: 2
$ g++-16 -std=c++23 -Wall -Wextra -Wpedantic count_fixed.cpp -o count_fixed && ./count_fixed
Boundaries: 2

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 count_fixed_session.py

It printed Boundaries: 2. In a header file, using namespace std; is never acceptable, because a header is pasted into every file that includes it: the directive then applies to code whose authors never wrote it and cannot undo it. The C++ Core Guidelines make this their rule SF.7, which rules out a global using namespace in any header, and their rule SF.6 keeps it elsewhere for transition, for foundation libraries such as std, or for a local scope. Google’s style guide forbids using-directives altogether, and LLVM’s says its code never uses using namespace std;.

Comments: why, not what

A comment that repeats the code goes stale and helps nobody: ++boundaries; // add one to boundaries. A useful comment says what the code cannot: why it does something, what it assumes, or what the reader would otherwise get wrong. The Core Guidelines make this two rules: NL.1 keeps out of comments what the code already says clearly, and NL.2 asks comments to state the intent. boundaries.cpp has two comments of that kind, on its purpose and on when read_runs stops reading. Good names make most other comments unnecessary.

Exercise: format and rename a program

This program works and prints 73.6667, but it breaks almost every rule of this lesson:

scores.cpp C++ · style/scores.cpp
#include<iostream>
#include<vector>
using namespace std;
int CNT=0;
double AVG(vector<int> V){double S=0;for(int i=0;i<V.size();i++){S=S+V[i];}return S/V.size();}
int main(){vector<int> MarksList={72,85,64};
cout<<AVG(MarksList)<<endl;}

Copy it, together with _clang-format, into a folder of your own. Then:

  1. Remove using namespace std; and write std:: names.
  2. Rename everything in the track’s style, remove the unused global, and take the vector as const std::vector<int>& instead of copying it.
  3. Run clang-format -i scores.cpp, then check with clang-format --dry-run --Werror scores.cpp, which must print nothing.

The program must still print 73.6667, and it must build without warnings with -std=c++23 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror.

One solution

scores.cpp in the track's style C++ · style/scores_solution.cpp
#include <iostream>
#include <vector>

double average(const std::vector<int>& marks) {
    double sum = 0;
    for (int mark : marks) {
        sum += mark;
    }
    return sum / static_cast<double>(marks.size());
}

int main() {
    const std::vector<int> marks{72, 85, 64};
    std::cout << average(marks) << '\n';
}
The original, then the solution with every flag Python · scores_session.py
from session import run

run("""
clang++ -std=c++23 style/scores.cpp -o scores && ./scores
clang++ -std=c++23 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror style/scores_solution.cpp -o scores_solution && ./scores_solution
g++-16 -std=c++23 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror style/scores_solution.cpp -o scores_solution && ./scores_solution
""")

Output

$ clang++ -std=c++23 style/scores.cpp -o scores && ./scores
73.6667
$ clang++ -std=c++23 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror style/scores_solution.cpp -o scores_solution && ./scores_solution
73.6667
$ g++-16 -std=c++23 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror style/scores_solution.cpp -o scores_solution && ./scores_solution
73.6667

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 scores_session.py

It printed 73.6667, built without a warning under those flags with both compilers, and clang-format --dry-run --Werror printed nothing for it. The range-based for also removed the comparison of an int with size().

Check yourself

Check yourself

4 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 4 A variable is declared inside the braces of an if statement. Where can it be used?

    Choose one answer.

    Show the answer to question 1

    Answer: Only inside that block, up to its closing brace

    A name's scope ends at the closing brace of the block that declares it. The lesson's bonus, declared inside the if block, was unknown on the line after the block: "use of undeclared identifier 'bonus'".

  2. Question 2 of 4 Which of these names should a program never declare? Choose every one.

    Choose every answer that is right.

    Show the answer to question 2

    Answer:

    • _Total
    • run__count

    The standard reserves every name that begins with an underscore followed by a capital letter, and every name that contains a double underscore, for the compiler and its library. total_runs and TotalRuns are ordinary names in two different styles.

  3. Question 3 of 4 Which command checks, without changing anything, that a file already follows the project's .clang-format, and fails if it does not?

    Choose one answer.

    Show the answer to question 3

    Answer: clang-format --dry-run --Werror main.cpp

    --dry-run makes no changes and reports each place that is not formatted, and --Werror turns those reports into errors, so the command fails. -i rewrites the file, and --dump-config prints the style settings.

  4. Question 4 of 4 A program with using namespace std; and a global variable named count fails with "reference to 'count' is ambiguous", although it includes only <iostream>. Why?

    Choose one answer.

    Show the answer to question 4

    Answer: <iostream> brings in std::count from the algorithms library, and the directive makes it visible as count

    Both standard libraries' <iostream> include parts of the algorithms library, so std::count is declared. The using-directive makes every std name usable without std::, and the two counts collide. Writing std:: names or choosing a more specific name avoids it.

Interview questions

Why should a header never contain using namespace std;? (warm-up)

A header is copied into every file that includes it, so a using-directive in it applies to all of those files, including ones written by people who never asked for it and cannot remove it. Every name of std then competes with their own names: a global variable called count, distance or size becomes ambiguous with std::count, std::distance or std::size, and the error appears in their code, far from the header that caused it. Which names clash also depends on what the standard library’s headers happen to include, so code can break after a compiler upgrade. Rule SF.7 of the C++ Core Guidelines rules out a global using-directive in a header for this reason. In a header, write std:: names; in a source file, prefer them too, or a using std::name; declaration.

Key takeaways

  • Lay out a file as: purpose comment, includes, constants, declarations, a short main, then the helper functions.
  • A name declared in a block ends at the block’s closing brace; declare each name in the smallest scope that needs it.
  • Use one naming style everywhere; this track uses the standard library’s snake_case. Never begin a name with an underscore and a capital letter, or use a double underscore.
  • clang-format sets the layout from a .clang-format file: -i to rewrite, --dry-run --Werror to check in CI. It fixes layout, not names.
  • using namespace std; made a global count ambiguous with std::count with only <iostream> included; write std:: names, and never put the directive in a header.
  • Comments should say why, not repeat what the code says.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.