Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Just enough C++ I: values, decisions, loops and functions

~35 min

Every chapter after this one shows you a small piece of C++ next to the machine code a compiler made from it. To follow those pairs you need to read C++ comfortably, not write large programs in it. This section and the next teach just the C++ the course uses. If you know Java or C#, much of it will look familiar. If you know Python, the shapes are the same, and the spelling is new.

Variables, types and fixed-width integers

A variable is a labelled box that holds a value. In C++ you have to say what kind of value goes in the box when you make it. That "kind" is called its type. Here's how you make a box called count, meant for whole numbers, holding 3 to begin with:

int count = 3;

Read it left to right: the kind of box (int, short for integer, a whole number), its name (count), and what it starts with (3). The semicolon at the end finishes the statement, the way a full stop ends a sentence. Once a box has a kind, it keeps that kind forever. An int box can't later hold text.

Here's a catch. The C++ rules don't fix how much room an int takes. Computers store numbers as rows of tiny switches, each one either 0 or 1. Those switches are called bits, and Chapter 2 is all about them. For now, just know that more bits means room for bigger numbers. An int is 32 bits on almost every computer today, but the rules only promise 16. This course cares about what the chip holds, so it uses kinds of box whose size is written in the name. These are fixed-width integer types: whole-number kinds with a fixed number of bits.

Take std::uint8_t apart:

  • std:: means "from C++'s standard library".
  • u means unsigned: it can't hold negative numbers.
  • int means whole numbers.
  • 8 means 8 bits of room.
  • _t is just a naming habit that marks a type.

So it's an unsigned whole number in 8 bits, which holds 0 up to 255. Drop the u (std::int8_t) and the same 8 bits have to cover negative numbers too. So it runs from −128 up to 127 instead. The table shows the sizes this course uses. To use them, a program starts with the line #include <cstdint>.

Sums work the way you'd expect, with +, - and *. Division has a twist. When both numbers are whole numbers, / gives a whole-number answer and throws the remainder away: 7 / 2 is 3, not 3.5. With a negative number it still chops toward zero, so -7 / 2 is -3. The % sign gives the remainder that was thrown away: 7 % 2 is 1. With a negative number on the left, the remainder is negative too: -7 % 2 is -1.

If you come from Python, watch out. Python's // rounds down instead, so -7 // 2 is -4 in Python, and its -7 % 2 is 1. Java and C# behave like C++.

Two shortcuts show up everywhere. total += 5 means "add 5 to total". ++i means "add 1 to i".

To show a value on the screen, this section writes std::cout << value << '\n';. Read std::cout << as "print this", and '\n' as "then go to a new line". The next section explains printing properly.

A value is one piece of data, such as 3 or true. This section covers values first. Then come decisions, loops and functions. A decision is a point where the program picks one of two paths. A loop is code that repeats. A function is a named piece of code you can call.

A variable is a named place that holds a value. A C++ declaration names its type, then its name, then (optionally) a starting value:

int count = 3;

This reads "make a variable called count, of type int, starting at 3". A type says what kind of value a variable holds. It fixes how much room the value takes and which operations make sense on it. int holds whole numbers. bool holds true or false. In C++ a variable's type is fixed when it's declared and never changes. Every statement ends with a semicolon.

The trouble with int is that the C++ rules don't say exactly how big it is, only that it's at least 16 bits (16 on/off positions, each 0 or 1; Chapter 2 builds this idea properly). It's 32 bits on every desktop and phone you're likely to use, but the rule doesn't promise that. This course looks at values as the processor holds them, so it uses fixed-width integer types, whose size is part of the name. They come from the header <cstdint>:

Name Size Can be negative? Range
std::int8_t 8 bits yes −128 to 127
std::uint8_t 8 bits no 0 to 255
std::int16_t 16 bits yes −32,768 to 32,767
std::uint16_t 16 bits no 0 to 65,535
std::int32_t 32 bits yes about ±2.1 billion
std::uint32_t 32 bits no 0 to about 4.3 billion
std::int64_t 64 bits yes about ±9.2 quintillion
std::uint64_t 64 bits no 0 to about 18.4 quintillion

Read the name in pieces: std:: (it belongs to the standard library), u if present (unsigned: no negative values), int, the size in bits, and _t (a naming habit for type names). So std::uint8_t is "an unsigned whole number, 8 bits wide". An unsigned type spends all of its room on zero and up, which is why std::uint8_t reaches 255 while std::int8_t stops at 127. Chapters 2 and 3 show how those ranges come out of the bits.

Arithmetic on integers uses +, -, *, / and %. Two rules catch people coming from other languages:

  1. / on two integers gives a whole number. It throws away the remainder, rounding toward zero: 7 / 2 is 3, and -7 / 2 is -3.
  2. % gives the remainder, and its sign follows the left-hand number: 7 % 2 is 1, -7 % 2 is -1.

Python's // rounds down instead (-7 // 2 is -4) and its % follows the right-hand number (-7 % 2 is 1). Java and C# match C++. Shorthand forms update a variable in place: total += 5 means total = total + 5, and ++i adds one to i.

To show a value, this section uses std::cout << value << '\n';. Read std::cout << as "print", and '\n' as "then start a new line". The next section covers printing properly.

Four bars of small boxes, one per type: std::int8_t with 8 boxes and range -128 to 127; std::int16_t with 16 boxes and range -32,768 to 32,767; std::int32_t with 32 boxes, about -2.1 billion to 2.1 billion; std::int64_t with 64 boxes, about -9.2 quintillion to 9.2 quintillion. A note says each small box is one 0-or-1 position and a u in front means no negatives.
The number in the name is the size. Twice the size gives far more than twice the range.
#include <cstdint>
#include <iostream>

int main() {
    std::int32_t apples = 7;
    std::int32_t boxes = 2;
    std::int32_t per_box = apples / boxes;
    std::int32_t left_over = apples % boxes;
    std::cout << per_box << '\n';
    std::cout << left_over << '\n';
    std::cout << -7 / 2 << '\n';
    std::cout << -7 % 2 << '\n';
}
3
1
-3
-1

Predict before you peek

Type exactly what the program prints, one line per line. The answer came from compiling and running it with a real C++ compiler.

Loading interactive…

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Correct answer

Also accepted:

Why

Why

23 / 5 is 4 with the remainder thrown away, and 23 % 5 is that remainder, 3. Then pages += 2 makes pages 25, and 25 / 5 is exactly 5.

Worked example

Reading a declaration piece by piece

  1. 1

    Read std::uint16_t port = 8080; aloud.

  2. 2

    The type comes first: std::uint16_t. The u says unsigned, so no negative values. 16 says 16 bits. Its range is 0 to 65,535.

  3. 3

    The name is port, and its starting value is 8080, which fits inside that range.

  4. 4

    In words: "an unsigned whole number, 16 bits wide, called port, starting at 8080". Java's only unsigned 16-bit type is char, meant for characters, so in Java you'd normally use int. In C# it's ushort port = 8080;.

Worked example

The Python reader's division trap

  1. 1

    A Python programmer expects std::cout << -9 / 4 << '\n'; to print -3, because Python's -9 // 4 is -3.

  2. 2

    C++ divides and then chops toward zero. −9 ÷ 4 is −2.25, and chopping toward zero gives -2.

  3. 3

    Python's // rounds down, toward minus infinity, and the next whole number below −2.25 is −3.

  4. 4

    For positive numbers the two agree (9 / 4 is 2 in both). They only part ways when a value is negative, so check the sign before predicting. In Chapter 8 you'll see the processor's divide step does the same chopping as C++.

Check your understanding (counts toward your progress)

What is the largest value a std::uint8_t can hold?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

There are 256 different values, but counting starts at 0, so the largest is one less.

127 is the top of std::int8_t, which also has to make room for negatives.

8 is the size in bits, not the largest value.

Why

std::uint8_t is unsigned and 8 bits wide, holding 0 to 255. Its signed partner std::int8_t covers −128 to 127 instead.

It's unsigned, so it starts at 0.

In std::int32_t total = 0;, which part is the type?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

total is the variable's name.

0 is the starting value.

The semicolon ends the statement.

Why

std::int32_t is the type (a whole number, 32 bits wide). total is the name, and 0 is the starting value.

A declaration reads: type, then name, then starting value.

Five billion doesn't fit in a std::int32_t. Fill in a type that holds it.

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Why

std::int64_t (or std::uint64_t) has 64 bits and reaches about 9.2 quintillion. By contrast, std::int32_t stops near 2.1 billion and std::uint32_t near 4.3 billion, so neither holds 5 billion.

Correct answer

Also accepted:

Why

Check the table: which size reaches past 5 billion?

What does the u in std::uint16_t tell you?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

Every fixed-width type has a fixed size; that's the 16. The u says something else.

It starts at 0, so it holds small numbers too.

The size is fixed and written right in the name.

Why

u means unsigned: no negative values, so all the room goes to zero and up. std::uint16_t holds 0 to 65,535.

Compare the ranges of std::int8_t and std::uint8_t.

Practice: Variables, types and arithmetic (5 problems · doesn’t affect your progress)

Which line makes a variable called level holding 3?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

The type comes first, then the name.

The name goes before the =, and the value after it.

The type starts the declaration; it isn't a value to store.

Why

A declaration is type, name, then = and the starting value: std::int32_t level = 3;

Type, name, =, value, semicolon.

std::int32_t level = 3;

What is the value of 23 % 4 in C++?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

Why

Five 4s make 20, leaving 3. % gives the remainder, so 23 % 4 is 3.

Correct answer

Also accepted:

Why

How many whole 4s fit in 23, and what's left?

3

Follow the changes to x. What does this print?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Why

x goes 10, then 15 (+= 5), then 16 (++x), then 16 / 4 = 4.

Correct answer

Also accepted:

Why

Write x after each line: 10, then 15, then ...

4 ⏎

Which of these types can hold the value −200?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

Unsigned types can't hold negatives at all.

std::int8_t stops at −128.

One of them is signed and far wider than 8 bits.

Why

Only a signed type holds negatives, and std::int8_t stops at −128. std::int32_t reaches about −2.1 billion.

It must be signed, and reach below −128.

std::int32_t

Translate the Java long ms = 3000000000L; into C++ with a fixed-width type.

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

Three billion is past the limit for 32 bits, about 2.1 billion.

A declaration names one type, not two.

16 bits stop at 32,767.

Why

Java's long is 64 bits wide and signed, which is std::int64_t in C++. Three billion fits easily.

Java's long is a whole number 64 bits wide.

std::int64_t ms = 3000000000;

Decisions, loops and functions

Normally C++ does one statement after another, top to bottom. Three tools change that order.

if and else make a choice. if (score >= 50) asks a yes-or-no question. If the answer is yes, the block in curly braces { } right after it runs. If not, the block after else runs instead. The question uses comparison signs. == means "is equal to" (two equals signs, because one = means "store this value"). != means "is not equal to", and <, <=, >, >= mean what they do in maths. && means "and", || means "or", and ! means "not".

while repeats. while (n > 1) { ... } checks the question, runs the block if the answer is yes, then checks again, over and over, until the answer is no.

for counts. for (std::int32_t i = 1; i <= n; ++i) has three parts between its round brackets. The first, std::int32_t i = 1, makes a counter called i starting at 1. The second, i <= n, is the question asked before each pass: keep going while i is at most n. The third, ++i, adds one to the counter after each pass. So the block runs with i equal to 1, then 2, and so on up to n.

A function is a named, reusable piece of code. You hand it some values, it does its work, and it can hand one value back. square below takes one whole number, called x inside the function, and hands back x times x:

std::int32_t square(std::int32_t x) { return x * x; }

The first std::int32_t is the kind of value it hands back. The inputs it expects are listed in the round brackets, each with its kind. These inputs are called parameters. return means "stop here and hand back this value". When the program says square(6), the function runs with x equal to 6 and hands back 36. If a function hands nothing back, its kind is written void. Every C++ program has a function called main. That's where the program begins.

C++ runs statements top to bottom unless something changes the order. Three constructs do that.

if / else runs one block or another, depending on a condition. Conditions compare values with == (equal), != (not equal), <, <=, >, >=, and combine them with && (and), || (or) and ! (not). Braces { } mark each block; indentation is for readers only. A chain is written else if.

while (condition) { ... } checks the condition, runs the block if it's true, and repeats until the condition is false.

for (start; condition; step) { ... } is a counting loop. for (std::int32_t i = 1; i <= n; ++i) makes i start at 1, runs the block while i <= n, and adds one to i after each pass.

A function is a named piece of code that takes inputs and can hand back a result. Its definition gives the result's type, the name, the parameters (inputs, each with a type) in parentheses, and a body:

#include <cstdint>

std::int32_t square(std::int32_t x) {
    return x * x;
}

return ends the function and hands back a value. Calling square(6) runs the body with x set to 6, and the call is replaced by the result, 36. A function that hands back nothing has the result type void. Every program has one function called main, and that's where it starts.

The same ideas in the languages you may already know:

Idea Java / C# Python C++
a whole number, 32 bits int n = 5; n = 5 std::int32_t n = 5;
a whole number, 64 bits long n = 5; n = 5 (no size limit) std::int64_t n = 5;
choose if (a < b) { ... } else if ... if a < b: ... elif if (a < b) { ... } else if ...
and, or, not &&, ||, ! and, or, not &&, ||, !
count 0 to 9 for (int i = 0; i < 10; i++) for i in range(10): for (std::int32_t i = 0; i < 10; ++i)
whole-number division 7 / 2 is 3 7 // 2 is 3 7 / 2 is 3
define a function static int sq(int x) { return x * x; } def sq(x): return x * x std::int32_t sq(std::int32_t x) { return x * x; }
print and end the line System.out.println(n); / Console.WriteLine(n); print(n) std::cout << n << '\n';
#include <cstdint>
#include <iostream>

std::int32_t sum_to(std::int32_t n) {
    std::int32_t total = 0;
    for (std::int32_t i = 1; i <= n; ++i) {
        total += i;
    }
    return total;
}

int main() {
    std::int32_t result = sum_to(4);
    if (result > 5) {
        std::cout << "big: " << result << '\n';
    } else {
        std::cout << "small: " << result << '\n';
    }
}
big: 10

Worked example

Tracing the loop in sum_to(4)

  1. 1

    Keep a table with one row per pass. total starts at 0.

  2. 2

    Pass 1: i is 1, and 1 <= 4 is true, so total becomes 0 + 1 = 1. Pass 2: i is 2, total becomes 3. Pass 3: i is 3, total becomes 6. Pass 4: i is 4, total becomes 10.

  3. 3

    After pass 4, ++i makes i 5. The check 5 <= 4 is false, so the loop ends without a fifth pass.

  4. 4

    return total; hands back 10. In main, result is 10, 10 > 5 is true, and the program prints big: 10. A trace table like this is the same tool Chapter 10 uses to follow a loop in machine code.

Build the function

Put the lines in order to make a function that counts how many times 3 can be taken away from n before n reaches zero or below. The counter must start before the loop, and the result is handed back after it.

Loading interactive…

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Correct answer

Also accepted:

Why

Why

The function line opens it. steps must exist (starting at 0) before the loop uses it. Inside the while block, take 3 away and count the step, in either order, since neither line touches the other's variable. The loop's closing brace comes before return steps;, so the count is handed back once, after the loop ends.

Worked example

Translating a Python function

  1. 1

    A Python function: def halvings(n): with the body steps = 0, while n > 1: n = n // 2; steps += 1, return steps.

  2. 2

    Give every value a type. n and the count are whole numbers that stay small, so std::int32_t fits. The function hands back a whole number, so its result type is std::int32_t too.

  3. 3

    Replace Python's colon-and-indent blocks with braces, end each statement with ;, and use / for whole-number division. Since n stays positive here, C++'s / and Python's // agree: std::int32_t halvings(std::int32_t n) { std::int32_t steps = 0; while (n > 1) { n = n / 2; ++steps; } return steps; }

  4. 4

    Check with n = 40: 40, 20, 10, 5, 2, 1. That's five halvings, so it returns 5 in both languages.

Check your understanding (counts toward your progress)

Order the lines to make a function that hands back the larger of two whole numbers.

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Why

When a > b, return a; ends the function. Otherwise the if block is skipped and return b; runs. Either way, exactly one value is handed back.

Correct answer

Also accepted:

Why

If a is bigger, hand it back straight away. Otherwise, the function carries on to the line after the if block.

How many times does the block of for (std::int32_t i = 0; i < 5; ++i) { ... } run?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

List the values: 0, 1, 2, 3, 4. That's more than four.

When i reaches 5, i < 5 is false, so there's no pass for 5.

The ++i step makes i grow until the condition fails.

Why

i takes 0, 1, 2, 3 and 4, which is five passes. Starting at 0 with < n gives exactly n passes.

Write down every value of i for which i < 5 is true.

Which condition is true exactly when x equals 10?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

A single = stores 10 in x. Comparing needs two equals signs.

!= means "is not equal to", the opposite.

C++ has no => at all; "at least" is written >=.

Why

== compares. A single = stores a value, which is a different statement altogether.

One = stores; how is "is equal to" written?

Which C++ loop does the same as Python's for i in range(3, 11, 2):?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

range stops before its end value, but <= lets i reach 11 too: 3, 5, 7, 9, 11 is one value too many.

++i steps by 1 (3, 4, 5, ... 10), but range's third number makes the step 2.

range(start, stop, step) starts at 3 and steps by 2. This swaps them and gives 2, 5, 8.

Why

range(3, 11, 2) gives 3, 5, 7, 9: start at 3, stop before 11, step 2. In C++: i = 3; i < 11; i += 2.

range(start, stop, step): stop is never reached.

Practice: Decisions, loops and functions (5 problems · doesn’t affect your progress)

What does != mean in a condition?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

That's ==.

That's a single =.

C++ has no such comparison.

Why

!= is true when the two values differ.

! means not.

Is not equal to

A function called twice. What does this print?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Why

square(3) hands back 9 and square(4) hands back 16, so the line prints 25.

Correct answer

Also accepted:

Why

Replace each call with what it hands back.

25 ⏎

What does void mean in void greet(std::int32_t times)?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

It takes one parameter, times. void is about the result.

Its body can do work, such as printing; it just doesn't hand a value back.

It's the opposite: there is no value at all.

Why

void in the result position means the function hands back no value. It can still do work.

void sits where the result type goes.

greet hands nothing back

Squares added in a loop. What does the program print?

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Why

The loop adds 1, 4 and 9, so total is 14.

Correct answer

Also accepted:

Why

Add 1×1, 2×2 and 3×3.

14 ⏎

Fill in the loop's condition so the program prints 3, 2 and 1, one per line, and stops.

Correct! 🎉 Not quite.

Right on try — credit. Right — the answer had already been shown, so no credit this time. Next try is worth Answer shown after three tries — this one no longer earns credit. You chose to see the answer — this one earns no credit.

What this task checks

Structure checked automatically. Whether your ideas are convincing isn't graded, so reread with the checklist.

The compiler says

A model answer

Why

i counts down 3, 2, 1, 0. The condition must be true for 3, 2 and 1 and false for 0: i > 0.

Correct answer

Also accepted:

Why

The block should run for 3, 2 and 1, and not for 0.

i > 0

Where this goes next

Chapter 2 §5 and Chapter 3 open up the fixed-width types: where 255 and −128 come from, and what happens one step past them. Chapter 8 shows the processor's add, multiply and divide steps, including the chop toward zero. Chapter 9 turns if/else into machine-code jumps. Chapter 10 does the same for while and for, and Chapters 11 and 12 show what calling a function and return really do.

Feeling good about this section?

Take the section quiz

Every answer gets a full explanation at the end.

Sign in to save highlights

Insert an equation

  • No matches.