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".umeans unsigned: it can't hold negative numbers.intmeans whole numbers.8means 8 bits of room._tis 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:
/on two integers gives a whole number. It throws away the remainder, rounding toward zero:7 / 2is3, and-7 / 2is-3.%gives the remainder, and its sign follows the left-hand number:7 % 2is1,-7 % 2is-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.
#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…
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
pages += 2 makes pages 25, and 25 / 5 is exactly 5.Worked example
Reading a declaration piece by piece
-
1
Read
std::uint16_t port = 8080;aloud. -
2
The type comes first:
std::uint16_t. Theusays unsigned, so no negative values.16says 16 bits. Its range is 0 to 65,535. -
3
The name is
port, and its starting value is8080, which fits inside that range. -
4
In words: "an unsigned whole number, 16 bits wide, called
port, starting at 8080". Java's only unsigned 16-bit type ischar, meant for characters, so in Java you'd normally useint. In C# it'sushort port = 8080;.
Worked example
The Python reader's division trap
-
1
A Python programmer expects
std::cout << -9 / 4 << '\n';to print-3, because Python's-9 // 4is-3. -
2
C++ divides and then chops toward zero. −9 ÷ 4 is −2.25, and chopping toward zero gives
-2. -
3
Python's
//rounds down, toward minus infinity, and the next whole number below −2.25 is −3. -
4
For positive numbers the two agree (
9 / 4is2in 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?
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?
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.
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?
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?
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++?
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?
Follow the changes to x. What does this print?
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?
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.
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
Keep a table with one row per pass.
totalstarts at 0. -
2
Pass 1:
iis 1, and1 <= 4is true, sototalbecomes 0 + 1 = 1. Pass 2:iis 2,totalbecomes 3. Pass 3:iis 3,totalbecomes 6. Pass 4:iis 4,totalbecomes 10. -
3
After pass 4,
++imakesi5. The check5 <= 4is false, so the loop ends without a fifth pass. -
4
return total;hands back 10. Inmain,resultis 10,10 > 5is true, and the program printsbig: 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…
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
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
A Python function:
def halvings(n):with the bodysteps = 0,while n > 1: n = n // 2; steps += 1,return steps. -
2
Give every value a type.
nand the count are whole numbers that stay small, sostd::int32_tfits. The function hands back a whole number, so its result type isstd::int32_ttoo. -
3
Replace Python's colon-and-indent blocks with braces, end each statement with
;, and use/for whole-number division. Sincenstays 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
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.
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?
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?
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):?
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?
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?
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)?
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?
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.
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.