Control in C++

Tips for navigating the slides:
  • Press O or Escape for overview mode.
  • Press the copy icon on the upper right of code blocks to copy the code

Class outline:

  • Miscellaneous
  • Conditional
  • Recursion
  • Iteration
  • Vectors
  • Exercises

Miscellaneous

Increment/Decrement Operator

In Python when we want to increase a value by 1 we do one of the following:


                    value = value + 1
                    

                    value += 1
                    

In C++ both of the above also work, but there is a shorter way using the increment operator ++:


                    value++;     // +1
                    

Now you know why the language after C is called C++ 😁

C++ also has a decrement operator -- that subracts one from the value in the variable.

Pre vs Post Increment

The increment and decrement unary operators can come before or after the variable name. The only difference between the two operators is how the expression is evaluated:


                    int num = 1;
                    
                    printf("num++ is: %d", num++);   // print value of num *before* the +1
                    printf("++num is: %d", ++num);   // print value of num *after* the +1
                    

Conditional

Conditional Statement

The following Python and C++ functions are equivalent


                    def sum_digits(n):
                        """Return the sum of the digits of positive integer n.
                        >>> sum_digits(6)
                        6
                        >>> sum_digits(2021)
                        5
                        """
                        if n < 10:
                            return n
                        else:
                            all_but_last = n // 10
                            last = n % 10
                            return sum_digits(all_but_last) + last
                    

                    /**
                     * Return the sum of the digits of positive integer n.
                     * Ex: sum_digits(6) == 6
                     * Ex: sum_digits(2021) == 5
                     */
                    int sum_digits(int n) {
                        if (n < 10) {
                            return n;
                        }
                        else {
                            int all_but_last = n / 10;
                            int last = n % 10;
                            return sum_digits(all_but_last) + last;
                        }
                    }
                    

Note that in C++ the parentheses ( ) are required around the if expression.

Note that in C++ you use braces { } instead of the colon : for statements after the if and else.

Nested if/else

The following Python and C++ functions are equivalent


                    if temperature < 0:
                        clothing = "snowsuit"
                    elif temperature < 32:
                        clothing = "jacket"
                    else:
                        clothing = "shirt"
                    

                    std::string clothing;
                    
                    if (temperature < 0) {
                        clothing = "snowsuit";
                    }
                    else if (temperature < 32) {
                        clothing = "jacket";
                    }
                    else {
                        clothing = "shirt";
                    }
                    

Note that in C++ there is no elif, just nested if/else blocks.

Note that in C++ we need to declare the string variable before using it in the if/else blocks.

Recursion

Recursion with Helper Function


                    def fact(n):
                        """ Compute the factorial !n recursively. 
                        >>> fact(2)
                        2
                        >>> fact(3)
                        6
                        >>> fact(6)
                        720
                        """
                        if n <= 0:
                            raise ValueError("Sorry, 'n' must be positive.")
                        def inner_fact(n):
                            return inner_fact(n-1) * n if n > 0 else 1
                        return inner_fact(n)
                    

                    int inner_fact(int n) {
                        if (n > 0) {
                            return inner_fact(n-1) * n;
                        } else {
                            return 1;
                        }
                    }

                    int fact(int n) {
                        if (n <= 0) {
                            throw std::invalid_argument("Sorry, 'n' must be positive.");
                        }
                        return inner_fact(n);
                    }
                    

Note that the C++ function inner_fact is callable by any function.

You need to have #include <stdexcept> at the top of your file to use std::invalid_argument.

⚠️ WARNING ⚠️ Order matters in C++, so inner_fact must be defined before fact, otherwise the code will not compile.<

Lambda (Annonymous) Functions

C++11 (published in 2011) added support for lambda functions 😍, but it is verbose 😒


                    #include <functional>   // need for `std::function`

                    int fact(int n) {
                        if (n <= 0) {
                            throw std::invalid_argument("Sorry, 'n' must be positive.");
                        }
                        // declare the types and name for the lambda function 
                        std::function<int(int)> inner_fact = [&inner_fact](int n) -> int
                        {
                            if (n > 0) {
                                return inner_fact(n-1) * n;
                            } else {
                                return 1;
                            }
                        };   // need a semicolon at the end of the lambda
                        return inner_fact(n);
                    }
                    

The [&inner_fact] part of the lambda is required for recursion.

std::function<int(int)> says that the function returns an int and has one parameter which is type int.

Lambda Function Syntax

Here is the EBNF for simple lambda functions:

"[]" "(" [TYPE identifier ["," TYPE identifier]*] ")" [ "->" TYPE] "{" statements "}"

                    auto sum = [] (int first, int second) -> int
                    {
                        return first + second;
                    };
                    printf("13 + 14 = %d", sum(13, 14));
                    

Note that instead of using std::function you can use the auto keyword in C++14.

The return type, which is after the ->, is optional if C++ can determine the type. This lambda function will work in place of the one above because both parameters are int:


                    [] (int first, int second)   // no `-> int` needed; can be inferred
                    {
                        return first + second;
                    };
                    

Iteration

While Statement

while statements in C++ are very similar to Python:


                    def fact(n):
                        total = 1
                        k = 1
                        while k <= n:
                            total *= k
                            k += 1
                        return total
                    

                    int fact(int n) {
                        int total = 1;
                        int k = 1;
                        while (k <= n) {
                            total *= k;
                            k += 1;
                        }
                        return total;
                    }
                    

The braces after the while statement aren't required if we only want one statement executed. The braces allow us to execute multiple statements and are considered best practice even for single statement bodies.

For Statement

for statements in C++ are not very similar to Python:


                    def sum_up_to(n):
                        """Returns the sum of positive
                        numbers from 1 up to N (inclusive).
                        >>> sum_up_to(5)
                        15
                        """ 
                        sum = 0
                        for i in range(0, n+1):
                            sum += i
                        return sum
                    

                    int sum_up_to(int n) {
                        int sum = 0;
                        for (int i = 0; i < n + 1; i++) {
                            sum += i;
                        }
                        return sum;
                    }
                    

Note the C++ for statement has three parts: for (initialization; condition; iteration) { ... }

Anatomy of For Statement

Syntax Part When Executed Description
initialization Once on entry into for loop. Next thing executed is the condition. Usually used to define the variable used as the counter (common practice is to call it i).
condition Before execution of all statements in the for loop. Next thing executed is the first statement inside the for loop body. Compare the loop counter to some bound. Similar to the condition of a while loop.
iteration (a.k.a. update) After the last statement inside the for loop body. Next thing executed is the condition. Usually used to increment or decrement the loop counter. Can modify loop counter in any way, e.g. i += 2 skips every other value of i.

For and Arrays

for statements are often used with arrays.


                    #include <cstdio>
                    const int MAX_SIZE = 50;
                    
                    void zeroize(int array[MAX_SIZE]) {
                        for (int i = 0; i < MAX_SIZE; i++) {
                            array[i] = 0;
                        }
                    }

                    int main() {
                        int values[MAX_SIZE];
                        zeroize(values);
                        printf("Last should be zero, is: %d\n", values[MAX_SIZE-1]);  // will be 0
                        return 0;
                    }
                    

Note that the size of the array is a global constant used by the function zeroize. If we want the function to work for any size array we would write it as:

void zeroize(int array[], int size) { ... }

Vectors

Vectors

The Standary Library vector class is similar to a Python list. You must have #include <vector> at the top of your file to use vectors.

It is common to use vectors over arrays, since vectors can grow dynamically and they keep track of their size.


                    tas = ["Haylee", "Easton", "Dallin", "Savannah"]
                    

                    std::vector<std::string> tas{"Haylee", "Easton", "Dallin", "Savannah"};
                    

⚠️ WARNING ⚠️ A vector object can only store elements of a single, specified type unlike Python lists.

Vector Methods

Here are some common methods provided by the vector class:

Method Parameter(s) Description
at int — index Accesses the specified element with bounds checking
push_back Value with same type as elements Add new value to the end of vector
pop_back (none) Remove the last element (not returned)
clear (none) Clears the contents
empty (none) Returns true if empty, false otherwise
size (none) Returns an unsigned integer type with number of elements

Has front and back like string and many more. See C++ Reference.

Indexing: Vectors and Strings

Both strings and vectors have two methods for accessing individual characters or elements.

The first way is to use brackets [ ], same as Python strings and lists:


                    std::vector<std::string> tas{"Haylee", "Easton", "Dallin", "Savannah"};
                    printf("%c", tas[0][2]);    // prints 'y'
                    

The second way is to the method .at():


                    std::vector<std::string> tas{"Haylee", "Easton", "Dallin", "Savannah"};
                    printf("%c", tas.at(2).at(0));    // prints 'D'
                    

The method .at() performs bounds checking 👀 which means it will throw an exception if the index is out of range (too big) for the size of the string or vector. This provides protection against malicious buffer overflow attacks 💣. Using [ ] is faster, but unsafe.

Printing Output

There are two different ways to print output.

We've already seen printf which is similar to format strings in Python, but printf doesn't play well with the C++ string class.

The C++ iostream library does work well with C++ strings.


                    #include <iostream>

                    int main() {
                        std::string name = "Brett";
                        
                        printf("%s\n", name);           // prints garabage chars like �HDQ�
                        printf("%s\n", name.c_str());   // prints "Brett" from C-style string
                        std::cout << name << std::endl; // prints "Brett"
                        return 0;
                    }
                    

cout stands for console or character output.

endl stands for end line.

For Each Statement

The for each statement is used with vectors and other collections that are iterable.

Python for each loop


                    for <value> in <sequence>:
                        <statement>
                        <statement>
                    

C++ for each loop


                    for (<TYPE> <value> : <sequence>) {
                        <statement>
                        <statement>
                    }
                    

                    std::vector<std::string> tas{"Haylee", "Easton", "Dallin", "Savannah"};
                    for (std::string ta : tas) {
                        std::cout << "Thank you, " << ta << "!" << std::endl;
                    }
                    

Why two ways for everything?

C++ often has multiple syntax options for the same thing because of the decision to be backward compatible with C code (C++ has everything in C and then more).

Exercises

Exercise: While loop

Create a C++ program equivalent to the following Python program:


                    def sum_digits(n):
                        digit_sum = 0
                        while n > 0:
                            last = n % 10
                            n = n // 10
                            digit_sum += last
                        return digit_sum
                    

Exercise: While loop (solution)


                    def sum_digits(n):
                        digit_sum = 0
                        while n > 0:
                            last = n % 10
                            n = n // 10
                            digit_sum += last
                        return digit_sum
                    

                    int sum_digits(int n) {
                        int digit_sum = 0;
                        while (n > 0) {
                            int last = n % 10;
                            int n = n / 10;
                            digit_sum += last;
                        }
                        return digit_sum;
                    }
                    

Exercise: Fast exponentiation

Create a C++ program equivalent to the following Python program:


                    def exp_fast(b, n):
                        if n == 0:
                            return 1
                        elif n % 2 == 0:
                            return square(exp_fast(b, n // 2))
                        else:
                            return b * exp_fast(b, n-1) 

                    square = lambda x: x * x
                    

Exercise: Fast exponentiation (solution)


                    auto square = [] (auto x) { return x * x; };

                    int exp_fast(int b, int n) {
                        if (n == 0) {
                            return 1;
                        }
                        else if (n % 2 == 0) {
                            return square(exp_fast(b, n / 2));
                        }
                        else {
                            return b * exp_fast(b, n-1);
                        }
                    }
                    

⚠️ WARNING ⚠️ Order matters in C++, so square must be defined before exp_fast, otherwise the code will not compile.