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

  • Shiva

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

    Quiz #1 felt pretty straightforward, but Quiz #2 was the real fun! I tried to make use of almost everything I learned so far from Alex, and here's the result:

    - gameFunctions.h -

    - gameFunctions.cpp -

    - gameHiLo.cpp -

    It looks pretty similar to Alex's own solution, as well many others's above.

    Question: is the default statement in the switch inside my playAgain() function totally pointless? As I've marked in the comments, I know it is superfluous since the loop iterates without it as indented if the control reaches there. But I felt including that made the logic clearer. Or am I being too fussy?

    Any other suggestions welcome too. :)

    • Alex

      Yes, the default case is superfluous because your switch is already at the end of the loop. However, it doesn't really do any harm either, and if being able to document that case makes you feel better, then go with it.

      • Shiva

        That's the expert's opinion we all need. Thanks Alex!

        And I hope the rest of the solution is overall okay. That's almost everything I've learned from here so far. :)

  • Alex

    So I mostly used the same code for question 1 as above, however, I found that using || on my conditionals in the while loop meant that my loop would run until both height and time had been satisfied, whereas && would terminate when only one of the conditions was met. Surely the behaviour should be the other way round?

  • saeid

    in quiz 2 i replaced this code :

    whit mine code :

    and my program work correctly . is it ane need to declare

    and make if statement work with that ???

  • Dyablo

    For Q1, I went with a for loop but I probably broke a "rule" about functions being too complicated, but at least it works haha:

  • Lokesh

    For Quiz Q1., I think this is more modular:

  • Sandro

    "* Visual Studio users: Due to a flaw in the Visual Studio implementation of rand(), call rand() once after seeding to discard the first result."

    I don't think this is only a VS problem. I use Code::Blocks and the rand() function returns the same number as before, plus something.

    I also need to call two times to recieve a more randon number.

  • Aymen

    Hi, Alex. big supporter. My bro actually introduced me to this website 2 months ago and slowly but surely going through it, you might remember he says he used to talk to you quite a lot back in the day (Shemseddine) anyways, I tried accomplishing this task using a for loop and was stuck for a long time and then thought to use a while loop. Why is this

    not acceptable - its an infinite loop but i cant seem to see why.
    Anyways thanks for the help and looking forward to finishing this series and learning so much :)

    • Alex

      You never set heightNow, so if heightNow is ever >0, it will always be >0.

      • Aymen

        I did, maybe I should of posted the full code but everything is the same apart from my calculateAndPrintHeight function.

        Again much thanks for your help, I got so frustrated with myself of not being able to do it I'v started this chapter again to refresh myself and hopefully have a better crack at it at the end.

        EDIT: PS how do assign expressions to an if statement
        for example in free pascal I do

        and

        and if the if statement returns true it executes everything withing the begin and end.

        With c++ to my understanding is that this

        would give me an output of 5, so what can I do to avoid this and organize my code.

        • Aymen

          I managed to figure it out , but I'm absolutely certain that its bad programming.

          • Alex

            There are a few things that are wrong with this:
            1) You're using the comma operator in a while statement, which is very unconventional. Comma also evaluates to the rightmost operand, so your while statement essentially evaluates to while (time++).
            2) You shouldn't need the if (heightNow == 0) statement if you fix the loop condition
            3) since heightNow is a double, you shouldn't use the equality operator. Use <= instead in case of floating point error.

        • Alex

          Regarding if statements, operator= is used for assignment. Operator== is used for comparison. So you'd want your if statement to look like this:

          • Aymen

            Ahh I get it now, much thanks!, I'v seen that alot of people in the comments could not complete the random number generator problem. I tried accomplishing the task but not using the techniques learnt in your lessons (well one, mersenne). I got an error on two different occasions so I did this instead - is it still valid or bad code again?

            Anyway's if anyone cant seem to get the mersenne function to work, I think my solution works fairly well.

            much thanks again!

            • Alex

              srand() should only be called once at the start of the program. Yours is inside the do loop.
              Also, the way you're doing your random numbers will result in a slightly uneven distribution (low numbers will come up slightly more often than higher numbers) but that shouldn't matter for this exercise since it's not important to have an even distribution.

  • Nathan

    No idea if you still post in here, but this was my solution. I just finished first year of computer science and I'm just going through your
    guides to touch up on my skills and make sure I understand most things.

    I still don't feel like I'm as good as I should be after one year of university so I'm still looking to be ahead for next year.

    If you are still replying, some feedback on the layout & design of my code would be nice.

    Thanks =)

  • Mistorcha

    Well, thanks a lot for this C++ tutorial, it's far better than the one in french I found so far.
    After looking for the correction, it look's like I'm close to what you did, I have just a question about the getRandomNumber.
    When you first spoke about having a random number between a mini and a maxi, in my mind it looked like :

    Is something wrong with this fonction?

    Thanks a lot for your time.
    Btw, sorry for the "far to be" fluent english.

    • Alex

      Yes, if maxi-mini isn't a divisor of the largest number generated by rand(), you get lopsided results due to the modulo (where some numbers are slightly more likely to occur than others).

  • Nortski

    Haha, well I got a solution to question 2. Not very elegant though :p

    • Nortski

      Oops, disregard

      in the playGame function.
      That was just to tell me what the random number was, for testing purposes.

  • Chris

    this is my solution for number 2.  I just wanna ask you what are the bad things about my solution? it is fine use void instead bool like yours on play() function? and my main() is  so short because few statement placed in other function, it is good or bad? Thank you.

  • Makar

    paragraph 3.5 says this is bad, but it is still used in reference solution to 1)

    • Alex

      In general, doing equality/inequality comparisons with floating point numbers is dangerous.

      However, this is one of the few cases where it works, since:
      * 0.0 can always be represented exactly in floating point.
      * We're not doing any math operations on currentHeight between the point where we assign 0.0 to it, and the point where we check if it's set to 0.0 (so there's no chance to accumulate floating point errors).

  • Victor

    I find the solution to 1st question a bit too large. I did it that way: (Back in chapter 2)

    constants.h

    main.cpp

    PS: With two additions, printout the exact hit time at the end and restart the whole program at it’s end.

  • Sean Kelly

    Hello Alex, for the first question I took another route from what you put as the answer and I wanted to see if this was a bad choice. Also, just so you know, I am currently using cpp.sh as my compiler due to the fact I am unable to get to my main computer at this time and the one I am using is a little weird when it comes to visual studio, so there is no header for this program.

    • Alex

      This looks fine. The use of a different variable for the loop counter and loop condition is clever.

    • Shiva

      Yeah, the logic behind that for-loop is really nice. Elegant thought.

      One thing that occurred to me though is, you don't need to call the function twice inside the loop. Instead,

      can optimise the code. IMHO this looks a little bit better logically as well.

      Hope that helps. :)

  • Lukas

  • bio

    something is wrong with the RNG ,it just keeps showing the same number for two or three intervals

  • Annibale

    Just a comment from a mathematician … nice game: you always win :D

  • Jazz

    Hi, Alex.

    It seems to me, that "do-while statement", is more appropriate for quiz number 2, because a statement checks the condition   after it has been executed at least once.

    Please tell me, if there are any mistakes in this code:
    *I'm using C::B for Windows*

    • Alex

      Yes, on reflection, I agree with you. I've updated the example.

      • Jazz

        Alex, thank you for your answer, and I have the last question related to quiz number two, and to programing generally. Is there some kind of "gold" code, in case if needed to choose between 3 conditions? Is there a shorthand method for doing a particular type of "if/else if/else" statement? It seems to me, that there are a lot of "more"-"less"-"equal" cases in programing.

        • Alex

          Not really. Most common thing to do is:

          I'd advise against using the conditional operator to do these tri-state conditionals, as they're harder to follow and easier to inadvertently mess up.

  • cesare

    Hi Alex, first of all thanks so much for your work.

    I have a question about the 2nd quiz (high low game), particularly for my function 'playAgain'.
    I preferred to implement it using std::string instead of char but I got an unexpected result.
    When the function is called it prints "Would you like to play again (y/n)? " twice, and I really don't understand why. Can you help me please.

    This is my complete program, anyway I think the issue is inside 'playAgain' as the rest works as expected.

    • cesare

      Another little question.
      How can I change 'getNumber' function to be sure the user typed a number instead of a character.
      I tried typing a character and the program seems to get into an infinite loop inside 'playAgain' function.
      Any hint will be appreciated.
      Thx

      • Alex

        After the user enters a number, you can check to see whether it succeeded:

        Put this inside a loop to keep asking the user for input until cin doesn't fail.

        • cesare

          Ok, I got it. I understand that I should be careful when using std::cin, and have to be aware of it's behavior with the buffer.
          About the std::cin buffer, is 32767 its maximum size?
          This is my new implementation and it seems to work properly.
          If there's a better way please let me know.
          Thx again.

          • Alex

            The maximum stream size can be accessed like this: std::numeric_limits::max(), which lives in the limits header.

            So technically, you should do this:

            You'll only need to use this if you think you'll have more data in your buffer than 32767 chars.

    • Alex

      The problem is that when you enter a number previously, the '\n' character that the user entered is still in the input stream. So the first time you read the stream to get the user input into your string, it reads the '\n' into your string and continues. This doesn't match your conditional, so it loops one more time. Now the stream is empty, so it waits for user input.

      You can fix this by removing the '\n' from the stream before asking the user if they want to play again, like this:

  • Josh

    Hey Alex, I need your opinion. I have been using your tutorials to learn C++ and I can't quite seem to do the two quiz questions above. I have been able to do all the quizzes before these. Do you think I should keep reading on or not proceed until I can complete these quizzes? Some things I asked myself after attempting to write those programs and failing, and after checking the correct answers was: how did you know that some of those functions needed to be of the bool type? When I was attempting both of them, I didn't even think of doing that. Is there a certain way to think when I read the questions, that will tell me what kinds of functions and what not to use? I feel like if I had a teacher for this, I could learn it no problem but it is kind of hard learning it on my own. I think my main problem is converting what you want me to do in the quiz question into the actual code but I have gotten better! So, thank you very much for your tutorials!

    • Alex

      The quizzes in this section are harder than the ones that you've seen previously.

      That's intentional: they are designed to challenge you and force you to stretch a bit.

      Even if you don't get it right, as you learn from your mistakes, and can understand why I did something the way I did, you can move on.

      If you don't understand why I did something the way I did, ask.

      > Is there a certain way to think when I read the questions, that will tell me what kinds of functions and what not to use?

      Figuring out how to structure your programs is something that takes practice. For me, I usually ask: "what are the main things this program needs to do?" and those become functions. If any of those things are complicated or need to be done more than once, they get broken down into smaller functions. From there, it's just a matter of understanding how to use parameters and return values effectively.

  • !coder

    This is my solution, without following all the hints. Please tell me guys, how bad is it?

    • Alex

      srand() should only be called once at the start of your program, so it needs to be outside the loop.

      Your code is hard to follow because you have loops inside of loops. Functions would be good here.

      I also think the continue at the end of main() may be unnecessary.

  • Call me "mat"

    Heyho, Alex!

    i’ve solved the 2nd problem and this is my solution :

    like what you can see there, i got some different algorithma from yours.
    so, i wanna ask you what are the bad things about my solution? except the use of "goto" of course.. i use it because im a little bit stuck on how to ask player to play again.. haha.

    thx before.. your tutorials are great :3

    • Alex

      I see a couple of things:
      1) You should only call srand() once. Your srand() gets called every game.
      2) Your main() function is a bit long -- if you broke it up into more functions, then I think you'd have an easier time using a loop to replay instead of goto.

      • Chad22

        Hi Alex,
        Is this good practice (to use the static variable) or should I just move the first two statements to the main function?

  • You can actually solve the equation for "seconds" of the "Ball falling from a tower" problem, and let the height == 0.
    Then you can post the exact time-elapsed when the ball hits the ground.(Using Visual Studio 2015 Community)
    ========================================================================================================================

    // quiz2ques4.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"
    #include <iostream>
    #include "constants.h"
    #include "math.h"

    double getInitialHeight() {
        using namespace std;
        cout << "How high is the tower, in meters? ";
        double height(0.0);
        cin >> height;
        return height;
    }

    void printHeightChart(double height) {
        using namespace std;
        using namespace myConstants;
        double instantHeight = height;
        for (int seconds = 0; instantHeight >= 0 && seconds <= 10; seconds++) {
            instantHeight = height - myConstants::gravity * seconds * seconds / 2;
            if (instantHeight < 0.0) {
                double lastSeconds = (sqrt((2 * (height) / myConstants::gravity)));
                cout << "At " << lastSeconds << " seconds, the ball has landed."  << endl;
                break;
            }
                cout << "At " << seconds << " seconds, the ball is at " << (instantHeight > 0 ? instantHeight : 0) << " meters." << endl;
                
        }
        return;
    }

    int main()
    {
        double height = getInitialHeight();
        printHeightChart(height);
        return 0;
    }

  • Hello Alex, how are you

    I was recently trying to solve #2 and wrote this solution:

    Your solution is undoubtly the best one. I just want to ask you, is my program acceptable or I am doing something that shouldn't be done for #2 problem?

    • Alex

      Your program has a few issues:
      1) You should only call srand() once, not every time game() is run. Move it to the top of main().
      2) Avoid using goto. Use a loop instead.
      3) You call game() in two different places. Consolidate this into a do-while loop.
      4) I'm not sure why game() returns anything since you always return 0.
      5) You should avoid using system() calls.
      6) The if statement to determine whether the user has lost isn't needed. The user lost if the for loop terminated. So you can move the "you lost" string underneath the for loop and make it unconditional.

  • Can command prompt only print 296 lines? When I tried my solution (above posted) with a large input (1236549), it prints 296 lines of output and rest are not printed. I also noted that the only last 296 lines  were printed. For example: if my input is 1236549, the first line the program prints is "At 207 seconds, the ball is at height: 1.02659e+006" and the last line my program printed was "The ball is at height 0 meters now". I first thought that it's an overflow problem. I changed the double variables to long double but the result remained unaffected.  I then wrote this:

    Result was counting of numbers from 4 to 299 where each number was printed in a new line. Does all command prompts are limited to print maximum 296 lines or this is a machine specific problem? Whatever this is, because the whole tutorial seems to use non-gui programs, you should tell the readers about this limitation of CMD somewhere in this tutorial :-)

    • Alex

      The limitations of the console vary depending on operating system. In all likelihood, your program printed all of the lines, but the buffer on your console was set to only retain the last 296 lines. There's likely a way to change how large the console buffer is, but that's outside the scope of this tutorial. Ask Google. :)

  • Oops...I forgot to #include constants.h

  • The following is my solution:

    Could it be better?

  • Viv

    Hi! This tutorial is great and very useful. I am running into something odd in my solution to the first problem. It runs almost fine, except that it prints a seemingly random (but not infinite) number of "At (time) seconds, the ball is at height: 0" messages after the ball has hit the ground.

    This is my main function (everything else is the same as the original program):

    I agree that your solutions are quite a bit better, but I am curious as to why this is happening.

    • Alex

      You're calling calculateAndPrintHeight() with argument height instead of argument initialHeight.

      This is pretty straightforward to discover using the debugger.

  • JJ

    There seems to be an issue with this random number generator. It always gives 10 when you first run it.

    • Alex

      It sounds like maybe seeding the random number generator is failing for some reason.

      Can you tell me the following:
      * What compiler/OS are you running?
      * sizeof(time_t) on your system
      * sizeof(unsigned int) on your system
      * Whether static_cast<unsigned int>(time(0)) always comes out the same number?

      • JJ

        Let me first say thank you very much for writing and maintaining such a fantastic tutorial on C++. I am new to C++ and am learning a lot for your work.

        Here are the information you asked for:

        * What compiler/OS are you running?
          I am using the latest version of Xcode on the latest version of Mac OS X.

        * sizeof(time_t) on your system
          8

        * sizeof(unsigned int) on your system
          4

        * Whether static_cast<unsigned int>(time(0)) always comes out the same number?
          No. It changes every time I run it.

        By the way, I am not getting 10 anymore. I was consistently getting 11 about 20 minutes (maybe) after I posted my post. Today as of right now I am consistently getting 75 every time. Could it be that the seed changes rather slowly so the random number generated changes even slower?

        • Alex

          If static_cast<unsigned int>(time(0))) is coming out a different number every time you run your application, then your random number generator should generate a different sequence every time you run your program. However, from the symptoms you're seeing, it sounds like your seed value is only being changed periodically

          Are you sure static_cast<unsigned int>(time(0))) changes _every_time_ you run your program, and not just once every 20 minutes or so?

          Normally when casting a larger int to a smaller one, compilers truncate, keeping the low bits (which are the ones that change every second, in this case). Maybe your system is doing something else, since technically casting a larger int to a smaller one results in undefined behavior.

          Try this instead:

          and see what happens?

          • Viv

            I am having the same problem (in Visual Studio) and I tried what you suggested here. It still produces the same number every time it starts. I waited ten minutes, then tried it again, and the same problem occurred except that the repeated number was different (I just tried it again after typing up this comment, and the repeated number has changed again. Both times it went up by two). So I suppose it doesn't actually change every time the program is run, just every so often.

            • Alex

              It took a while, but I discovered the root cause of the issue.

              In Visual Studio, the first result of rand() is heavily dependent upon the seed value. Since the seed value from time() isn't changing much, the first result from rand() isn't changing much either. getRandomNumber() is then compressing that into the same number.

              After the first result, the sequence of numbers generated from rand() appears to be properly randomized.

              The easy solution is to discard the first result from rand(). I'll update the examples accordingly.

  • Marcel S

    Hey Alex,

    the second if is useless and gives out a compiler error
    anyways I love your tutorials thank you for making them!

Leave a Comment

Put all code inside code tags: [code]your code here[/code]