Summary and cleanup

Sections24
  1. Quick Tips
  2. Variables
  3. Data Types with Literals
  4. Primitive Types
  5. Data Types and Their Size
  6. Conversion
  7. Arithmetic
  8. Operator Precedence
  9. Functions
  10. void
  11. std::string
  12. const
  13. Comparison
  14. Boolean
  15. Negation
  16. Or
  17. And
  18. Control Flow
  19. if Statement
  20. else and else if
  21. while Loop
  22. do while Loop
  23. for Loop
  24. continue and break

Quick Tips§

How to deal with new syntax

Although this is a summary, I will add quick cleanup of details that I failed to introduce in previous tutorials. Whenever we encounter seemingly new syntax or control flow, always remember that we read code from top to bottom, literally line by line. Specific lines of code cannot be executed until we reach that line.

Variables§

int j;       // declaration
int i = 0;   // initialization
j = i;       // assignment

A declaration tells C++ that a variable exists and specifies its type.

An initialization gives a variable its first value when it is created.

An assignment changes the value of an existing variable.

Data Types with Literals§

Primitive Types§

short a = 3;                         // no special literal suffix
unsigned short b = 4;               // no special literal suffix
int c = 100;                         // without a suffix, this is an integer literal
signed int cc = 200;                 // the same as int; int is signed by default
unsigned int d = 1230045u;
long e = 5495829345982345l;
unsigned long f = 23453452345234624ul;
long long g = 452345234523452345ll;
unsigned long long h = 24589293452894578979429843592345ull;

float x = 3452.93f;
double y = 435345.534245;             // without a suffix, this is a double literal

char al = 'A';                        // char literal
unsigned char ual = 4;               // can also be used as a small numeric type

bool booleanValue = true;             // or false

The list above covers the basic primitive types used in ordinary C++ code. There are also library-specific types, operating-system-specific types, and other types that we will encounter later.

Note: Pointers are explicitly excluded from this summary and will be introduced later.

Data Types and Their Size§

The size of a type depends on the platform. The sizes below are the common sizes used on modern systems and are sufficient for our purposes.

bool;        // 1 byte
char;        // 1 byte
short;       // 2 bytes
int;         // 4 bytes
float;       // 4 bytes, approximately 7 digits of precision
long;        // 8 bytes
double;      // 8 bytes, approximately 15 digits of precision
long long;   // 8 bytes

Signed and unsigned versions of an integer type have the same size.

For a k-bit signed integer using the representation used by modern systems, the range is:

[−2k−1,2k−1−1][-2^{k-1}, 2^{k-1}-1]

For an unsigned integer:

[0,2k−1][0,2^k-1]

Note

These sizes and ranges are common rather than guaranteed for every possible C++ platform. Unusual, old, or custom systems may use different sizes.

Conversion§

If we want to convert one type into another, we can write:

float pi = 3.14f;
int k = int(pi); // k = 3

The floating-point value is converted to an integer, discarding the fractional part.

C++ can also perform implicit conversion when appropriate:

float x = 3.14;

Here, 3.14 is a double literal. C++ converts it to float when storing it in x.

Implicit conversion can sometimes cause unexpected results.

For example:

float q = 13 / 2; // q = 6, not 6.5

The division happens first:

13 / 2

Both operands are integers, so integer division produces 6.

Only afterward is the result converted to float:

6 → 6.0f

Another example:

int i = -1;
unsigned int j = 1;

if (i < j)
{
    // some code
}

You might expect -1 < 1 to be true.

However, before the comparison, i is converted to unsigned int. For a 32-bit unsigned int:

-1 → 4294967295

So the comparison effectively becomes:

4294967295 < 1

which is false.

C++ converts the value according to the rules of the destination type; it is not simply reinterpreting the same memory as another type.

Arithmetic§

int a = 6;
float b = 3.45f;

a + b; // addition:       9.45f
a - b; // subtraction:    2.55f
a / b; // division:       approximately 1.739
a * b; // multiplication: 20.7

a++;   // increases a by 1, so a is now 7
b--;   // decreases b by 1, so b is now 2.45f

a * b; // now uses the changed values of a and b

a % 3; // 1; 7 / 3 = 2 remainder 1
a % 4; // 3; 7 / 4 = 1 remainder 3

a += b; // roughly equivalent to a = a + b
a -= b; // roughly equivalent to a = a - b
a *= b; // roughly equivalent to a = a * b
a /= b; // roughly equivalent to a = a / b

% is the modulus operator. For integers, it gives the remainder after division.

++ increments a value by 1, while -- decrements it by 1.

Operator Precedence§

When multiple operators appear in one expression, C++ has rules that determine which operation happens first.

int x = 2 + 3 * 4; // 14

Multiplication happens before addition.

Parentheses can explicitly change the grouping:

int y = (2 + 3) * 4; // 20

When unsure about how an expression is grouped, parentheses can make the intended order explicit.

Functions§

A function can be declared, defined, and invoked.

int functionName(int argument, float arg); // declaration

int functionName(int argument, float arg) // definition
{
    return 3; // return statement
}

int result = functionName(34, 6.5f); // invocation

A declaration tells C++ that a function exists and describes its interface.

A definition provides the actual body of the function.

An invocation or function call executes the function.

Importantly, defining a function does not execute its body.

int add(int a, int b)
{
    return a + b; // not executed yet
}

std::print("Hello"); // executed first

int result = add(3, 5); // the function executes here

void§

Sometimes a function does not need to return a value.

We use void to indicate that the function does not return a value:

void print(std::string message)
{
    return; // ends the function
}

In a void function, return; can be used simply to end the function.

std::string§

std::string is a standard-library type used to represent text.

#include <string>

std::string name = "Alice";

It can also be used as a function parameter:

void print(std::string message)
{
    // ...
}

const§

const means that a variable cannot be modified after initialization.

const int x = 10;

x = 20; // error

The value of x must remain 10.

Comparison§

Comparison operators produce a Boolean result: either true or false.

a < b;  // true if a is less than b
a > b;  // true if a is greater than b
a >= b; // true if a is greater than or equal to b
a <= b; // true if a is less than or equal to b
a != b; // true if a is not equal to b
a == b; // true if a is equal to b

Be careful not to confuse:

a = b;  // assignment
a == b; // comparison

Boolean§

Boolean expressions can be combined using logical operators.

Negation§

if (!(a < b))

! means not.

Therefore:

!(a < b)

means:

a < b is not true.

Equivalently:

a >= b

Or§

if (a != b || a > b)

|| means or.

The expression is true if at least one of its conditions is true.

For example:

if (!(a < b) || a <= b)

can be rewritten as:

if (a >= b || a <= b)

At least one of these conditions must be true, so this particular condition is always true.

And§

if (a != b && a > b)

&& means and.

The entire expression is true only when both conditions are true.

For example:

if (!(a < b && a == b))

can be rewritten using the negation rules as:

if (a >= b || a != b)

This particular condition is also always true.

Control Flow§

if Statement§

if (boolean)
{
    // code executed when boolean is true
}

The body executes only if the condition evaluates to true.

else and else if§

if (condition)
{
    // executed if condition is true
}
else if (anotherCondition)
{
    // executed if the first condition is false
    // and this condition is true
}
else
{
    // executed if all previous conditions are false
}

Only the appropriate branch is executed.

while Loop§

int i = 0;

while (i < 10)
{
    std::print("{}", i);
    i++;
}

This loops 10 times.

The output is:

0123456789

The condition is checked before each iteration. Therefore, the loop can execute zero times.

do while Loop§

int i = 0;

do
{
    std::print("{}", i);
    i++;
}
while (i < 10);

This also outputs:

0123456789

The difference is that the condition is checked after the body.

Consider:

int i = 0;

while (i < 0)
{
    std::print("{}", i);
    i++;
}

The condition is false immediately, so nothing is printed.

Compare it with:

int i = 0;

do
{
    std::print("{}", i);
    i++;
}
while (i < 0);

The body executes once before the condition is checked, so the output is:

0

Therefore, a do while loop always executes its body at least once.

for Loop§

for (int i = 0; i < 10; i++)
{
    std::print("{}", i);
}

A for loop contains three parts:

initialization ; condition ; iteration expression

So the above can be thought of as:

int i = 0;

while (i < 10)
{
    std::print("{}", i);
    i++;
}

The output is:

0123456789

continue and break§

for (int i = 0; i < 10; i++)
{
    if (i == 3)
    {
        continue; // skip the rest of this iteration
    }

    std::print("{}", i);

    if (i == 5)
    {
        break; // exit the entire loop
    }
}

The output is:

0124

continue skips the rest of the current iteration and proceeds to the next iteration.

break exits the entire loop.

In a for loop, continue first reaches the loop's iteration expression:

i++

before checking the loop condition again.

So when i == 3:

continue
    ↓
i++
    ↓
i < 10
    ↓
next iteration

This is different from break, which immediately leaves the loop.

Discussion

no comments
Commenting as a guest — sign in to comment as yourself.

No comments yet — yours could open the discussion.