Search

7.x — Chapter 7 summary and quiz

Quick review

The specific sequence of statements that the CPU executes in a program is called the program’s execution path. A straight-line program takes the same path every time it is run.

Control flow statements (also called Flow control statements) allow the programmer to change the normal path of execution. When a control flow statement causes the program to begin executing some non-sequential instruction sequence, this is called a branch.

A conditional statement is a statement that specifies whether some associated statement(s) should be executed or not.

If statements allow us to execute an associated statement based on whether some condition is true. Else statements execute if the associated condition is false. You can chain together multiple if and else statements.

A dangling else occurs when it is ambiguous which if statement an else statement is connected to. Dangling else statements are matched up with the last unmatched if statement in the same block. Thus, we trivially avoid dangling else statements by ensuring the body of an if statement is placed in a block.

A null statement is a statement that consists of just a semicolon. It does nothing, and is used when the language requires a statement to exist but the programmer does not need the statement to do anything.

Switch statements provide a cleaner and faster method for selecting between a number of matching items. Switch statements only work with integral types. Case labels are used to identify the values for the evaluated condition to match. The statements beneath a default label are executed if no matching case label can be found.

When execution flows from a statement underneath a label into statements underneath a subsequent label, this is called fallthrough. A break statement (or return statement) can be used to prevent fallthrough. The [[fallthrough]] attribute can be used to document intentional fallthrough.

Goto statements allow the program to jump to somewhere else in the code, either forward or backwards. These should generally be avoided, as they can create spaghetti code, which occurs when a program has a path of execution that resembles a bowl of spaghetti.

While loops allow the program to loop as long as a given condition evaluates to true. The condition is evaluated before the loop executes.

An infinite loop is a loop that has a condition that always evaluates to true. These loops will loop forever unless another control flow statement is used to stop them.

A loop variable (also called a counter) is an integer variable used to count how many times a loop has executed. Each execution of a loop is called an iteration.

Do while loops are similar to while loops, but the condition is evaluated after the loop executes instead of before.

For loops are the most used loop, and are ideal when you need to loop a specific number of times. An off-by-one error occurs when the loop iterates one too many or one too few times.

Break statements allow us to break out of a switch, while, do while, or for loop (also range-based for loops, which we haven’t covered yet). Continue statements allow us to move immediately to the next loop iteration.

Halts allow us to terminate our program. Normal termination means the program has exited in an expected way (and the status code will indicate whether it succeeded or not). std::exit() is called at the end of main, or it can be called explicitly to terminate the program. It does some cleanup, but does not cleanup any local variables, or unwind the call stack.

Abnormal termination occurs when the program encountered some kind of unexpected error and had to be shut down. std::abort can be called for an abnormal termination.

Scope creep occurs when a project’s capabilities grow beyond what was originally intended at the start of the project or project phase.

Software verification is the process of testing whether or not the software works as expected in all cases. A unit test is a test designed to test a small portion of the code (typically a function or call) in isolation to ensure a particular behavior occurs as expected. Unit test frameworks can help you organize your unit tests. Integration testing tests the integration of a bunch of units together to ensure they work properly.

Code coverage refers to how much of the source code is executed while testing. Statement coverage refers to the percentage of statements in a program that have been exercised by testing routines. Branch coverage refers to the percentage of branches that have been executed by testing routines. Loop coverage (also called the 0, 1, 2 test) means that if you have a loop, you should ensure it works properly when it iterates 0 times, 1 time, and 2 times.

The happy path is the path of execution that occurs when there are no errors encountered. A sad path is one where an error or failure state occurs. A non-recoverable error (also called a fatal error) is an error that is severe enough that the program can’t continue running. A program that handles error cases well is robust.

A buffer is a piece of memory set aside for storing data temporarily while it is moved from one place to another.

The process of checking whether user input conforms to what the program is expecting is called input validation.

std::cerr is an output stream (like std::cout) designed to be used for error messages.

A precondition is any condition that must always be true prior to the execution of some segment of code. An invariant is a condition that must be true while some component is executing. A postcondition is any condition that must always be true after the execution of some code.

An assertion is an expression that will be true unless there is a bug in the program. In C++, runtime assertions are typically implemented using the assert preprocessor macro. Assertions are usually turned off in non-debug code. A static_assert is an assertion that is evaluated at compile-time.

Assertions should be used to document cases that should be logically impossible. Error handling should be used to handle cases that are possible.

Quiz time

Warning: The quizzes start getting harder from this point forward, but you can do it. Let’s rock these quizzes!

Question #1

In the chapter 4 comprehensive quiz, we wrote a program to simulate a ball falling off of a tower. Because we didn’t have loops yet, the ball could only fall for 5 seconds.

Take the program below and modify it so that the ball falls for as many seconds as needed until it reaches the ground.

In constants.h:

In your main code file:

Show Solution

Question #2

A prime number is a natural number greater than 1 that is evenly divisible (with no remainder) only by 1 and itself. Complete the following program by writing the isPrime() function using a for loop.

Show Solution


8.1 -- Using a language reference
Index
7.17 -- Assert and static_assert

819 comments to 7.x — Chapter 7 summary and quiz

  • kavin

    Hi, i was able to solve both the quizzes. Here is my solution for 2a and 2b combined. Let me know if its ok or there is anything i could improve ?

    And big thanks for teaching VS debugger in previous lessons, was so helpful in finding my mistakes in this program !

    Just saw your quiz answer. Looks like i should have changed lines 67-70 like this ?

    • nascardriver

      Hey kavin!

      Good job using the debugger to find your mistakes! Some suggestions:

      - Avoid recursion (A function calling itself) (`getInput` -> `playAgain` -> `getInput` -> ...). Use a loop instead.
      - Initialize variables with brace initialization (Line 69).
      - Magic number/string: 7. Add a constant.
      - Inconsistent formatting. Use your editor's auto-formatting feature (Might be at Edit->Advanced->Format Document).
      - Line 84: Should be '.' or ".\n".
      - Using `std::exit` can make the control flow harder to understand. Return a `bool` that causes the main loop to stop when the user doesn't want to play anymore.

      There's a big quiz coming up in the next chapter, keep it up!

  • Mn3m

    [code]#include <iostream>
    #include <random>
    #include <ctime>
    #include "constants.h"

    void replay();

    namespace MyRandom
        {
            
            std::mt19937 mersenne{ static_cast<std::mt19937::result_type>(std::time(nullptr)) };
        }

        int getRandomNumber(int min, int max)
        {
            std::uniform_int_distribution die{ min, max };
            return die(MyRandom::mersenne);
        }

        void startGame()
        {

            constexpr int attempts = 7;
            int correctAnswer = getRandomNumber(1, 100);
            std::cout << "Pssss... The correct answer is " << correctAnswer << '\n';//Just for me to verify that everything is alright :)
            std::cout << "Let's play a game. I'm thinking of a number. You have "<<attempts<<" tries to guess what it is.\n";
            int guess;

            for (int i = 1; i <= attempts; i++)
            {
                std::cout << "Guess# " << i << ':';
                std::cin >> guess;

                if (guess > correctAnswer)
                {
                    std::cout << "Your guess is too high.\n";
                }

                else if (guess < correctAnswer)
                {
                    std::cout << "Your guess is too low.\n";
                }

                else
                {
                 std::cout << "Correct! You won!\n";
                 replay();        
                }
                    
                  
            }

            std::cout << "You lost! The correct answer is: "<<correctAnswer<<'\n';
            replay();

        }

        void replay()
        {
            char choice;
            while (true)
            {        
                std::cout << "Would you like to play again? (y/n)";
                std::cin >> choice;

                if (choice == 'y')
                    startGame();
                else if (choice == 'n')
                {
                    std::cout << "Thank you for playing.";
                    exit(0);//Since I keep jumping between startGame() and replay() , the stack is messed up. I had to use exit(0) to terminate instead of a normal return;
                }
                else
                {
                    std::cin.ignore(32376,'\n');
                }
                
            }
        }

    int main()
    {
        startGame();
        return 0;
    } [code]

    Can you give me some feedback on this, please ? :)

  • Eric

    I did Question 1 somewhat differently (see below) than your answer.
    What are the advantages of the one way verses the other?

    • nascardriver

      Your `calculateHeight` isn't reusable, because it doesn't return the height and doesn't use `secondsPassed`. It also prints the height itself, so you can't use it without printing the height.

      Notes:
      - Initialize variables with brace initialization.
      - Use double literals for doubles (0.0 instead of 0).
      - `calculateHeight`'s return value and `secondsPassed` are unused.
      - Line 23 doesn't do anything.

      `getInitialHeight` and `printHeight` are pretty good, only `calculateHeight` does too much.

  • Suyash

    My solution (it's working as expected)... You are more than welcome to correct any mistakes that you spot in my code...

    • nascardriver

      Hi,

      Congrats on solving the quiz!

      Some suggestions:
      - Line 90: In the first iteration, this comparison is unnecessary. Moving the choice check to later or using a do-while loop could fix this.
      - Initialize variables with brace initialization for better type safety.
      - Magic numbers/strings: 1, 7, 100

  • Sinethemba

    Hi, I have managed to solve quiz question 2b. Below is my code solution. Any feedback would be highly appreciated.

    • nascardriver

      Hi!

      - Initialize variables with brace initialization (Line 84).
      - `user_value != number` in line 49 is always true. If the variables were equal, line 46 would have stopped the loop. You can change the `break` in line 46 to a `return` and move the "Sorry" message to after the loop. That way you don't have to compare the variables in every cycle of the loop.
      - `checkUserInput` doesn't check user input. "getUserInput" or similar describes the function better.

      The structure of your code is really good, keep it up!

  • Limerk

    Good Day! I finished reading all tutorials and finally started doing quiz. I would love to hear your criticism and/or suggestions about how I could improve my current solution to the given problem. Thank you in advance!

    • nascardriver

      Hello!

      - Don't use `std::endl` unless you need to.
      - Line 17 makes your code non-reusable. It's better to generate the number in a function that you can call in case you want to play multiple games.
      - Line 30,31 39,40 45,48: Duplicate code.
      - Line 34, 36, 42: Duplicate comparisons. You can use a `while (true)` loop to solve both of these issues.
      - Line 99: `(isGuessed && i == tries)` never gets evaluated. The condition stops of `isGuessed` is `true`.
      - If your program prints anything, the last thing it prints should be a line feed ('\n').

      • Limerk

        Thank you so much for your reply! Quick question. I always have duplicate code like in line 30, 31, 39, 40, 45, 48. The one way that I see how I could solve it, I could have created a function that would call this code in the place where I would need it, but this kind of solution seems for me as still a bad practice.... I want your opinion, in cases like this should I try to create a function and use it or it's better to try and change the program flow in order to get rid of these duplicates?

        • nascardriver

          Replacing these lines with a function is a good start. When you've done that, you'll still have a triple function call. That can happen, but it's an indicator that your control flow might not be the best. Try using a `while (true)` loop as I suggested before, that should get rid of the repetitions entirely. If you're having problems somewhere, please ask.

          • Limerk

            Ok. Thank you! I'm not afraid of the infinite loop but I didn't want to use it since in the book that I read, "C++ Primer Plus", author suggested that people should try to avoid it. I personally don't think they are too scary, I mean as long as you can terminate it there shouldn't be any problem

            • nascardriver

              An infinite loops isn't good indeed, but it's better than a repetition. Once you've sorted out your code to remove the repetitions, you good split your code into more functions, making your loop more readable, so it's easy to determine when the loop stops. Maybe you'll find a new termination condition after you cleaned up your code, then the infinite loop is gone too.

  • cnoob

    Hi! These tutorials are awesome! Ive just come up with another solution for 2a, and I would be more than happy to have some feedback.

    • nascardriver

      Hi!

      - Magic numbers/strings: 1, 7, 100. Define constants.
      - Avoid recursion (A function calling itself). Use a loop instead. (hiLoFunc, playAgain).
      - If your program prints anything, the last thing it prints should be a line feed.
      - Line 34 always compares true.

      • cnoob

        Wow, these problems would not have occured to me on my own! Ive just fixed the code according to your remarks. Thank you very much!

  • Chandler

    I had fun with this one. I cld've done more, made it cleaner and a little more polished, added a header or two, and maybe an enum class.
    Thanks to these well-written tutorials, I look forward to jumping out of bed and spending my day learning C++.
    Comments and suggestions will be appreciated.

    • nascardriver

      Congratulations on solving the quiz, I'm glad you're having fun :)

      - Compile-time constants should be `constexpr`.
      - Don't seed random number generators more than once. You won't get random numbers.
      - Line 64 always compares true.
      - Line 66+ is unreachable.
      - Line 34, 36: Duplicate comparison. Remove line 34, add an `else if` to check for `n`/'N'.
      - Use single quotation marks for characters (' ' vs " ").

      • Chandler

        Thanks for the feedback, nascardriver. I fixed the code and it now works as expected. Thanks.

      • chai

        hi there, what is your opinion on recursion? People say that recursion is good for code readability but not so good for performance. Is that true?Thanks.

        • nascardriver

          Many times recursion can be replaced with an equally readable or better readable loop. In certain cases, recursion can be easier to read.
          Recursion is bad for performance and suffers from memory exhaustion (There's only a certain number of recursive calls you can make before your program crashes).

          Avoid recursion, unless an iterative solution would be a huge mess.

  • Daki

    Hello!

    The code I wrote for 2a is different from the solution above and would appreciate any feedback or criticisms!

    • nascardriver

      - Magic number/string: 7
      - Line 70+: Duplicate comparisons and function calls. You can move the input validation into `contGame` and return a bool from `constGame`.
      - Line 31+: Duplicate comparisons. Use nested if-statements.

      Your code will be a lot easier to maintain without duplicates. If you have any questions, feel free to ask.

  • BakaTensi

    What do you think about my solution for 2b? I'm open for criticism. Here are some specific questions I'm concerned about:

    -Is my commenting style okay?
    -Have I broken down the code into too many or too few functions?
    -Is my solution to encase the game variables into a struct and then pass that into functions okay?
    -How can I make the random number generation in a way that it's still in a separate function but it doesn't get reseeded every time I start a new game?

    As a side note, I've disabled adblock, and it still doesn't show ads, only the place where they are supposed to be.

    • nascardriver

      > Is my commenting style okay?
      Limit lines to 80 characters in length for better readability. This doesn't affect only comments, but also code. Your editor probably has a setting to display a vertical line.
      The comments above functions are great. If you think you need a comment inside of a function, you should move the code into a separate function with a good name instead. You can remove your comments in `getUserGuess` and `playAgain` altogether, the code is easy enough.
      The comments above `GameVariables` should be above the variable that they refer to to make them easier to find.

      > Have I broken down the code into too many or too few functions?
      Line 42-46 and 121-125 are identical, they should be moved into a new function. The other functions look good.

      > Is my solution to encase the game variables into a struct and then pass that into functions okay?
      Yes.

      > How can I make the random number generation in a way that it's still in a separate function but it doesn't get reseeded every time I start a new game?
      `static` (Lesson S.4.3)

      - Line 30, 31: `return { /* ... */ }` allows for better optimization.
      - Line 36+ and 115+: Use a `while (true)` loop. A `do-while` loop makes the reader expect some condition at the end.

      Looks good overall :)

  • Ethan

    What do you think about this solution to 2a?

    • nascardriver

      - Line 47: Initialize with brace initialization.
      - Line 57 is always true. Should be just `else`.
      - Magic numbers/strings: 1, 7, 100

      Looks good otherwise :)

  • Adam

    What do you think?

    • nascardriver

      Hello Adam,

      - Initialize your variables with brace initializers.
      - Magic number/string: 7
      - Use ++prefix unless you need postfix++.
      - Line 59: Nice conditional operator!
      - Avoid static duration variables. They'll break your code when you get to object oriented programming or threading.

  • JamesWeb

    Hello, I have a question.
    Doesn't number and answer get created and destroyed each iteration?
    So I thought if it would be better to put them outside of the while loop?
    Also is there anything else in my code that I could improve or change?

    • nascardriver

      - Initialize your variables with brace initializers.
      - Seed random number generators only once. `getRandomNumber` isn't random.
      - Line 55: You don't need this variable, you can call `isGuesCorrect` in the if-statement.
      - Line 77, 78: Duplicate comparison of `answer` to 'y'.
      - Compile-time constants should be `constexpr`.

      > Doesn't number and answer get created and destroyed each iteration?
      No, your computer uses variables that never get created and never get destroyed, they're there all the time. Those variables are re-used across functions.

  • Shawn

    Hello, I wrote the answer to 2a) in a different way than you wrote. can you check this please? thanks.

    #include <iostream>
    #include <random>
    #include <ctime>

    enum class GuessRespnse
    {
        SUCCESS,
        FAILURE,
    };

    int getRandom(int min, int max)
    {
        
        static std::mt19937 mersenne(static_cast<std::mt19937::result_type>(std::time(nullptr)));
        std::uniform_int_distribution<> range(min, max);
        return range(mersenne);
        
    }

    int takeGuess(int guessID)
    {
        std::cout << "Guess #" << guessID << ": ";
        int guess;
        std::cin >> guess;
        
        return guess;
    }

    bool playAgainAsking()
    {
        while (true) //loop until user enters a vaild input
        {
            std::cout << "Would you like to play again(y / n) ? ";
            char another;
            std::cin >> another;

            std::cin.ignore(32767, '\n');
            
            if (another == 'y' || another == 'n')
                return another == 'y';
        }
    }

    //Check if the guess of the user is correct and return it by "GuessRespnse" enum
    GuessRespnse guessResponsing(int theRandom, int theGuess)
    {
        if (theRandom == theGuess)
        {
            std::cout << "Correct!You win!\n";
            return GuessRespnse::SUCCESS;
        }

        std::cout << "Your guess is too " << (theGuess < theRandom ? "low" : "high") << ".\n";
        return GuessRespnse::FAILURE;
    }

    //return if the user wants to play again
    bool playGame(int tries = 7, int min = 0, int max = 10)
    {
        std::cout << "Let's play a game. I'm thinking of a number. You have 7 tries to guess what it is\n";
        

        int random = getRandom(min, max);
        
        for (int count = 0; count < tries; count++)
        {
            int guess{ takeGuess(count) };
            
            if (guessResponsing(random, guess) == GuessRespnse::SUCCESS)
            {
                if (playAgainAsking())
                    return true;
                return false;
            }
        }
        return playAgainAsking();
    }

    int main()
    {
        while (playGame());
    }

    • nascardriver

      Hi!

      Please use code tags when posting code.

      - Initialize your variables with brace initializers.
      - Don't pass 32767 to `std::cin.ignore`. Pass `std::numeric_limits::max()`. Passing 32767 has no special meaning.
      - Line 39, 40: Duplicate comparison of `another` to 'y'.
      - Line 53: Nice.
      - Magic number/string: 7.
      - Use ++prefix unless you need postfix++.
      - Line 71-73: `return playAgainAsking();`.

      A lot of code editors offer a spell checker, see if you can get one.

      • Shawn

        Thanks for your reply
        1)I didn't understand if you mean to the initializing in the for loop or when I initialized variables(if I remember correctly at the beginning of the tutorial you recommended to initialize a variable only when you will use his value).
        4) thanks (:
        5) how do you recommend to do that?
        6) yeah, visual studio makes for loop automatically(for + tab + tab) and i didn't notice.
        7) lol

        • nascardriver

          Line 14, 15, 63 and 65 should use brace initialization.
          If you know that you're going to write to a variable before using it, you can omit the initialization. Initializing the anyway (To their default value, ie. empty curly braces) can help preventing hard-to-find errors.

  • Muirgheal Wen

    Hi Alex & nascardriver! Thanks for looking over so many people's code- I did a first pass at the solution myself, then checked against the provided solution, and looked over the comments you provided below.
    There were a few places where my solution and the provided one differs in terms of where we chose to put functions. I've marked them as comments below.
    Here's my solution for the Hi-Lo game.

    • - Initialize your variables with brace initializers.
      - Limit your lines to 80 characters in length for better readability.
      - Use `constexpr` for compile-time constants.
      - There's no reason to use `std::atoi` here. `std::cin >>` is fully capable of integer extraction.
      - Inconsistent formatting. Use your editor's auto-formatting feature.
      - Line 47 is always `true`.
      - Use ++prefix unless you need postfix++.
      - Line 84, 86, 89: Triple comparison of `play_again_switch` to `userQuit`. All three comparisons produce the same value. Line 86+ can be moved out of the loop.

      I don't understand your first comment. Can you tell me which line numbers of the solution and your code you're referring to?

      Configuring the game in `manager` is fine.

  • Parsa

    What is the difference between using if multiple times rather than using if once and then else if?

    And here is my hilo solution-

    • - Initialize your variables with brace initializers.
      - Limit your lines to 80 characters in length for better readability.
      - Don't use `goto`. Loops are easier to read.
      - Inconsistent formatting. Use your editor's auto-formatting feature.
      - Magic number/string: 7.
      - Seed random number generators only once.
      - Don't use `std::exit`.
      - Use ++prefix unless you need postfix++.
      - Line 63 always evaluates to true.
      - Line 28+, 45+: Duplicate code.
      - Line 41: `guess != randomNumber` is always true.

      • Parsa

        -I don't understand what I am supposed to do with the magic number 7.

        -Line 41 and 63: don't understand how it always evaluates to true.

        Thank you by the way.

        • > I don't understand what I am supposed to do with the magic number 7
          Add a `constexpr` variable and use that wherever you used 7.

          > don't understand how it always evaluates to true
          Line 41
          The check only runs if line 24 was `false`. If line 24 was false, then you already know that `guess != randomNumber`.

          Line 63
          You know `!(guess == randomNumber)` because of line 24.
          You know `!(guess < randomNumber)` because of line 59.
          The only relation that the two variables could have is `guess > randomNumber`.

  • Parsa

    When would it be better to use operator= versus brace initialization? Since they seem to be able to do different things.

  • `operator=` is used for assignments. I suppose you mean copy initialization.

    Always use brace initialization unless you can't (Because of `std::initializer_list`. Covered later).

  • alfonso

    My hi-lo solution:

    main.cpp

    functions.cpp

    functions.h

    globals.h

    • - Initialize your variables with brace initializers.
      - Limit your lines to 80 characters in length for better readability.
      - Don't pass 32767 to `std::cin.ignore`. Pass `std::numeric_limits<std::streamsize>::max()`.
      - `tooHigh`, `tooLow`, `itMatches`: That's what enums are there for.
      - functions.cpp:58+ and `guess`: You didn't gain anything from adding `guess`.
      - Use `switch` for limited sets of values.
      - functions.cpp:36,37: `std::swap`.
      - functions.cpp:46 Good use of the constant!
      - `userNumber` and `match` should be declared inside of the loop.
      - functions.cpp:84,85: Why do you assume an error when the input wasn't 'y' or 'n', but when the input is 'y' or 'n', you're sure there is no trailing input?
      - `seed` isn't a seed, it's a mersenne twister. The seed is the part you're initializing `seed` with.
      - You're using the same name style for variables and functions, this can lead to confusion.

      • alfonso

        > - Use `switch` for limited sets of values.

        I wanted to use keywords like break and continue inside the for loop, but depending on switch cases. So then break would apply to switch statement. Using if statement instead, I do not need to have care about conflicts using brake inside a switch inside a loop.

        > `userNumber` and `match` should be declared inside of the loop.

        I deleted match, and guess() function and tooHigh, tooLow global constants. Why I declared variables outside the loop: for performance reasons. Making the variable outside means making the variable once and then only assigning values in the loop for it. I braked the rule 'smallest scope as possible'.

        Thank you for your reply.

        Btw, I can win this game every time. :) If you choose right, at 6th move, you'll have two 'moves' and only two possible answers.

        • > switch
          functions.cpp:79+ Doesn't use `break` or `continue`.

          > Making the variable outside means making the variable once and then only assigning values in the loop for it
          This can be a valid argument for custom types, but not for fundamental types. The space of the variable is re-used, there is not creation or destruction of fundamental types. You're increasing the scope without gaining anything from it.

          > If you choose right, at 6th move, you'll have two 'moves' and only two possible answers.
          Good observation! This reminds me of a problem with an egg and a skyscraper. If you get into algorithms, you're bound to run into it.

  • Parsa

    This code won't compile ( I know my function and variable names aren't great and aren't consistent)

    • Always post error messages along with their line numbers.

      Brace initialization enforces fairly strict conversion rules. You can't initialize a `double` from an `int`. Add a `static_cast<double>`. Change the `2` in your `distanceFallen` calculations to a `2.0`. `2` is an integer, `2.0` is a `double`.

  • samtheham

    Hi Alex/Nascardriver! Thanks again for all the fantastic work on this site. If you could help me look over my code (Q2b) and let me know what improvements can be made, it would be greatly appreciated. My approach for the loops was a bit different from your solution, relying mostly on infinite loops and breaks rather than for statements. I do this mostly because I personally find it easier to follow the logic, but if there's good reason to use for statements instead, I'd appreciate the pointer. (Oh and I use #pragma once because I'm really lazy to type header guards for exercises, sorry) Code as follows:

    main.cpp:

    input.h:

    input.cpp:

    random.h:

    random.cpp:

    playagain.h:

    playagain.cpp:

    • - Limit your lines to 80 characters in length for better readability.
      - Initialize your variables with brace initializers.
      - Don't pass 32767 to @std::cin.ignore. Pass @std::numeric_limits<std::streamsize>::max().
      - Use `switch` for a limited set of values.
      - Use `constexpr` for compile-time constants.
      - input.cpp:18 isn't guarded by the `else`. Use your editor's auto-formatting feature, braces for `if`s, and enable warnings.
      - Magic string: 7.
      - "main.cpp" has a bunch of unnecessary includes.
      - main.cpp:29 always compares `true`.

      > good reason to use for statements
      Use what shows your intentions best. Doing so improves readability and allows the compiler to apply appropriate optimizations. `for` doesn't "leak" its iteration and (if you don't use `break`) it's easy to see when it will stop. If you use an infinite loop instead, the read has to read through the entire loop's body to see how long the loop will run.

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    This is my quiz no. 2. What do you think?