Chapter 7 - Worked Exercises

Create a function prototype for a function called max, that accepts an integer array and its length, and returns the largest element in the array.

Implement the function.

int main() {
    int numbers[10] = {1, 4, 13, 0, 7, 3, 20, 8, 2, 4};
    std::cout << "The maximum is " << max(numbers, 10) << std::endl;
    // The above should print 20
}

The function should return -1 if the array is empty.

Create a program that sums all the digits in a number:

Enter a number: 342
The sum of all the digits in 342 is 9. 

You should create two implementations of this program, one using a for-loop or while loop to perform the summing, and another using a recursive function.

The factorial function (symbol: !) is the product of all positive integers less than or equal to the number provided.

  • 5! is 5 * 4 * 3 * 2 * 1

  • 10! is 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1

Create a function, factorial, that computes the factorial of a number.

Your first implementation should use a for-loop or while-loop, and your second implementation should use recursion.

Below we have an example of a program that helps people split a restaurant bill equally amongst the people present:

#include <iostream>
#include <vector>

int main() {
    // Ask how many items 
    int numberOfItems = 0;
    std::cout << "How many items were ordered? ";
    std::cin >> numberOfItems; 
    
    // Ask for the price of each item 
    std::vector<int> itemPrices;
    int itemPrice = 0;
    for (int i = 0; i < numberOfItems; i++) {
        std::cout << "Please enter the price of Item " << i;
        std::cin >> itemPrice;
        itemPrices.push_back(itemPrice);
    }
    
    // Sum up all our prices 
    int totalCost = 0;
    for (int price: itemPrices) {
        totalCost += price;
    }
    
    // Ask how many people were present
    int numberOfPeople = 0;
    std::cout << "How many people should the bill be split by? ";
    std::cin >> numberOfPeople;
    
    float costPerPerson = totalCost / numberOfPeople;
    std::cout << "Each person should pay: " << costPerPerson << std::endl;
}

Your job is to improve the readability of this program, by abstracting some of code logically into separate functions.

Bonus: Can you also account for edge cases? What if the user enters 0 number of people? Should negative prices be allowed? Can we modify the program to allow decimals for the price of each item?

Task 1

Previously we've learned that functions have a name, can accept zero or more arguments, but can only return a single value.

So far we've learned that we can return multiple values using a certain method, what is this method?

Using this method, create a function called calculateAreaAndVolume that takes a float value corresponding to the length of the edge of a cube, calculates and returns the total area and volume of the cube.

Task 2

For each of the following, create a lambda that fits each of the function descriptions. Use sensible and descriptive variables that fit the function description.

Bonus: Declare explicitly the function pointer type instead of using auto

Example

Accepts 2 integer values, and returns the sum of the two.

auto sum = [](int a, int b){ return a + b; };
// Example:
int number = sum(3, 5); // `number` should be 8
  1. Accepts 3 integer values, and returns the largest value out of the 3.

  2. Accepts a Day enum value corresponding to days of the week, returns true if the day is a weekday, false otherwise.

  3. Accepts no parameters, but captures from the current scope a string variable called name, and prints the greeting "Hello there, name!"

  4. Accepts no parameters, but captures from the current scope a vector of integers called numbers, and sets each element in the vector to 0.

Task 3

For each of the following, qualitatively describe the lambda.

Example

auto concatenante = [](std::string first, std::string second) {
    return first + second;
}

A lambda function called concatenate that captures nothing, accepts two string parameters, and returns the concatenation of the two parameters.

  1. auto exists = [](std::vector<int> numbers, int numberToFind) {
        for (auto number: numbers) {
            if (number == numberToFind) {
                return true;
            }
        }
        return false;
    };
  2. auto accumulate = [method](std::vector<int> numbers) {
        if (method == "sum") {
            int sum = 0;
            for (auto number: numbers) {
                sum += number;
            }
            return sum;
        } 
        if (method == "multiply") {
            int sum = 1;
            for (auto number: numbers) {
                sum *= sum;
            }
            return sum;
        }
        return -1;
    };
  3. auto haveMoney = [moneyInWallet, moneyInBank, moneyInDrawer](){
        return moneyInWallet || moneyInBank || moneyInDrawer;
    };
  4. auto calculateAreaAndVolume = [&area, &volume] (int x) {
        area = x * x * 6;  // A cube has 6 sides 
        volume = x * x * x; 
    };

Task 4

We learned that function pointers allow us to store functions into variables. This also means that we can use these variables as part of arguments to other functions, in other words, passing a function into a function.

Consider the following program:

#include <string>
#include <iostream>

void greetHello(std::string name) {
    std::cout << "Hello, " << name << "!" << std::endl;
}

void greetSalutations(std::string name) {
    std::cout << "Salutations, " << name << "!" << std::endl;
}

int main() {
    std::cout << "What is your name? ";
    cin >> std::string name;
}

Usually we would call the following functions as greetHello(name) or greetSalutations(name), but instead your task is to create another function called apply that takes two arguments:

  • A function pointer argument for a void function that takes a single string argument

  • A string argument

And calls the function referred to by the function pointer, with the string argument provided.

For example, calling:

apply(greetHello, "Andrew"); 

Would result in "Hello, Andrew!" being printed to the console.

Solution

The syntax for using function pointers as function parameters is similar to the syntax for function pointers themselves:

<return_type>(*<parameter_name>)(<func_pointer_parameter_type>, ...)
void apply(void(*functionToCall)(std::string), std::string name) {
    functionToCall(name);
}

Last updated

Was this helpful?