# 5.x — Chapter 5 comprehensive quiz

Quick review

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

Switch statements provide a cleaner and faster method for selecting between a number of discrete items. Switch statements pair great with enumerations.

Goto statements allow the program to jump to somewhere else in the code. Don’t use these.

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

Do while loops are the same as while loops, but the condition is evaluated after the loop execution. They’re great for menus or things that need to execute at least once.

For loops are the most used loop, and are perfect when you need to loop a specific number of times.

Break statements allow us to break out of a `switch`, `while`, `do while`, or `for` loop. Or a range-based `for` loop, which we haven’t covered yet.

Continue statements allow us to move immediately to the next loop iteration. Be careful when using these with while and do while loops, as your loop counter may not get incremented properly.

And finally, random numbers give us a way to make our programs behave different each time they are run. We’ll see an example of this in the quiz below!

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 2 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:

Show Solution

Question #2

a) Implement a game of hi-lo. First, your program should pick a random integer between 1 and 100. The user is given 7 tries to guess the number.

If the user does not guess the correct number, the program should tell them whether they guessed too high or too low. If the user guesses the right number, the program should tell them they won. If they run out of guesses, the program should tell them they lost, and what the correct number is. At the end of the game, the user should be asked if they want to play again. If the user doesn’t enter ‘y’ or ‘n’, ask them again.

Note: You do not need to implement error handling for the user’s guess.

Here’s what your output should look like:

```Let's play a game.  I'm thinking of a number.  You have 7 tries to guess what it is.
Guess #1: 64
Guess #2: 32
Guess #3: 54
Guess #4: 51
Correct! You win!
Would you like to play again (y/n)? y
Let's play a game.  I'm thinking of a number.  You have 7 tries to guess what it is.
Guess #1: 64
Guess #2: 32
Guess #3: 54
Guess #4: 51
Guess #5: 36
Guess #6: 45
Guess #7: 48
Sorry, you lose.  The correct number was 49.
Would you like to play again (y/n)? q
Would you like to play again (y/n)? f
Would you like to play again (y/n)? n
Thank you for playing.
```

Hints:
* Use the Mersenne Twister algorithm from chapter 5.9 -- Random number generation to pick a random number.
* Write a function that allows the user to play a single game of hi-lo.
* Write a function that asks the user if they want to play again and handles the looping logic for an incorrect input.
* Avoid magic numbers by defining constants for the minimum/maximum random range and the number of guesses.
* In an if-statement, if you already checked 2 numbers for equality and compared them with either the < or > operator, but all checks failed, the relation between the numbers must be the one you didn’t check. For example, if `guess` is neither equal to nor less than `number`, it must be greater than `number`.

Show Solution

b) Update your previous solution to handle invalid input (e.g. ‘x’) or valid input with extraneous characters (e.g. “43x”) when the user is guessing a number.

Hint: Write a separate function to handle the user inputting their guess (along with the associated error handling).

Show Solution

 6.1 -- Arrays (Part I) Index 5.11 -- Introduction to testing your code

### 740 comments to 5.x — Chapter 5 comprehensive quiz

• RJ

Could someone critique my work I want to see how i'm progressing. I know there are many ways to solving problems in C++.

This program was separated into different files when i made it, but I posted it like this just to keep it simple.

• nascardriver

`GenerateRandomNumber` isn't random. Sees random number generators only once.
`&` is a bitwise and. You probably meant to use the modulus operator `%`.
Don't use goto, use loops.
Magic string: 7. Use your constant.
Use ++prefix unless you need postfix++. postfix++ is slower.
Use characters for characters. Using integers is wildly confusing.
Line 83 is always true on the first iteration. Use a do-while-loop instead.
Separate code into as many functions as possible to make it easier to read, maintain, and reuse.

• Saiyan

This is what I have. Thanks for sharing your knowledge. Always regretted dropping out of Intro to C++ so many years ago.

• nascardriver

Hi!

- Name variables descriptively. "x" isn't helpful.
- Compile-time constants should be `constexpr`.
- Line 59 is always true.
- The caller of `playAgain` shouldn't care about what the user input looked like. Return a `bool` instead. Then you can remove line 83 and 87 and just call `playAgain` in the main loop's condition.

• Saiyan

Thanks for the feedback! Regarding your last point, would something like this be more preferable?

• nascardriver

Yes, that's what I meant. Now the caller doesn't have to worry about how the user interface is implemented. Say you translate your program to french and you use 'o'/'n' as input. You just have to update `playAgain`, and not every call to it.

You never need an `if`-statement like this

it can and should be replaced with

You now have a duplicate comparison of `ch` to 'y'. That can be avoided by checking `ch` inside of the loop.

• M.J

Hello everyone.
This is question #2
i copied the code of part b and used it in my function to validate user input. however it shows zero and continues when i test invalid input. can anyone suggest solution?

• nascardriver

• M.J

yeh sorry about that, I updated.

• nascardriver

You're returning from your `while (true)` loop no matter what happened before. Even if you detect invalid input in line 32, you're returning in line 43.

Other notes:
- `generateRandomNumber` isn't random. Seed random number generators only once.
- Enable compiler warnings, read them, fix them.
- By returning a `char` from `getUserChoice`, you're forcing the caller to perform another check for 'y'/'n'. Return a `bool` instead.
- Use ++prefix unless you need postfix++. postfix++ is slower.
- Line 102 is always true.
- Line 106-120 and 126-142: Duplicate code.

If you have questions to any of those points, please ask. Feel free to post your code for review when you're done with the quiz :)

• M.J

I tried fixing most issues you mentioned. i tried getting rid of the extra duplicate code. i ended up with a smaller block of duplicate code :p
- i ran the program several times and got different random numbers, so i couldn't figure the random number generator's seeding part you mentioned.
- i have "w-error" activated in code blocks as mentioned in ch 0.11
the program runs fine now.
here is the updated version.
THANKS a lot for your efforts... much appreciated. :)

• nascardriver

> I tried fixing most issues you mentioned
- `generateRandomNumber`

Outputs the same number over and over again, because you're re-seeding `mersenne` every time, resulting in the random sequence being reset. Make `mersenne` `static` so it only gets created once no matter how often the function is called.

- compiler warnings
It looks like you're not compiling with -Wall -Wextra. There are still warnings, because the parameters of `gamePlay` are unused.

- getUserChoice
Looking good now :)

- Magic numbers/strings
Still there. Add a constant for `7`, use that in line 108, 112, 149.

- ++prefix
Yep, gone.

- Line 102 is always true
Correct fix

- Duplicate code
You can move the game part (Line 104-164, but without 132-140 and 153-161) into a new function. That will get rid of the duplicate code and the `goto`.

- Line 78 and 86 are basically returning the value of `userChoice`. You can remove these lines and add an unconditional `return userChoice;` to the end of `replay`.

• M.J

hey! thank you fro your note.
- I declared 'mersenne' in an namespace. as i saw it in one of the comments, that seems to have solved the issue with random number generation. thank your for pointing that out.
- I added the provided extensions to my compiler settings.
- i decided to go for a do while loop as it seems to have solved most problems lol :))
this is my final version of the code :)

p.s.
I want to solve more similar problems to try improve my logic and computational thinking before advancing to the next chapters. If you happen to have any useful resources on where i can find such. Please be generous.
Thank you again.. :)

• nascardriver

> logic and computational thinking
The best source to get that is by practice. Keep on programming and you'll get better.

Unless you're using notepad, your editor probably has a feature to auto-format your code. You should look into that.

• Raul T

Hi!
In the first instance I wanted to put the 'secondsPassed post-increment' in the for loop 'end-expression', but from that resulted in a small bug.
Assignment #1

• nascardriver

> I wanted to put the 'secondsPassed post-increment' in the for loop 'end-expression'
If you don't know how often a loop will run, a `while`-loop is usually the better choice.

• These lessons have been awesome! I have followed from the very first chapter, and I can tell my skills are better now. I hope to land a job with this skill. Take a look at my solution. Could I have done anything better?

constants.h

main.cpp

• Fosterwerks

Just wondering if my uses of const and static inside my version of startGame() are good uses or not. (Did not include the whole program for brevity). Thanks!

• nascardriver

Hi!

`mt` is right, but `dist` is problematic. `startGame` can be called multiple times, with different `numRange`. But `dist` is only created once, at doesn't care about any `numRange` after the first one.

• mindenki

Hey! Here is my solutioon for question #1? Is it any good?

• nascardriver

If it works, it's good.

Suggestions:
- Initialize variables with list initialization.
- Use double literals for doubles (0.0).
- Duplicate calculation of the current height. Add a variable.
- Line 22 and 24 break your program. The given formula calculates this distance fallen since the beginning.
- Line 32 is never false.

• mindenki

Thank you nascardriver

• Nathuunn

I made height a global variable, im wondering if thats okay, and if its not why?

• nascardriver

Global variables are bad, we explained why in lesson 6.9. You can get rid of it with minimal modifications to your code, just add a return value to `calculateAndPrintHeight`.
Avoid `static` local variable. `incrementSeconds` isn't reusable. Say you wanted to let the simulation run several times, each time asking the user for another height, you can't do that.

• veqes

Hello again! I had a go at Q2 and I ran into a really frustrating problem. I don't know how to avoid using goto at the end of my "win" condition. Could you please have a look at my code and give me some clues on how to avoid it in this case?
I'd appreciate feedback on the rest of the code as well if possible :)
Thank You!

• nascardriver

`getRandomNumber` isn't random. Don't re-seed random number generators.

Use `bool` with `false`/`true` for values that have only 2 options, not `int`.

When the number is correct, you can `break` the loop. Now you just have to move the "Sorry" message (Don't duplicate it!), or find a way of remembering the result until after the loop, so you only print the message when the user lost.

• Anto

i know it could be better, but i tried to change the least possible.

• nascardriver

Looks pretty good :)

• Gabe

Quiz 2

What could I have changed? I feel it could have been better.

constants.h

main.cpp

• nascardriver

- Initialize variables with list initialization.
- Magic string: 7
- "user_input" isn't a good name for what the function does. "play_game" or similar would be better.

If `validate_user_input` returns false, the user loses a guess. If that's not what you intended, you could decrement `count` in the event of an input failure or use a different kind of loop.
Your play again loop is good, many people get this part wrong ;)

• Gabe

Thanks again! Yeah I was aware of the "user loses a guess" part;however, I thought my code was a bit messy the way it was already, so I didn't add it I guess.

Also, for the "magic string, " I should have added the NUM_OF_GUESS instead?

• nascardriver

You already have NUM_OF_GUESS, you just need to print it.

• Sahib

Can I get some feedback?

• nascardriver

- Inconsistent formatting. Use your editor's auto-formatting feature.
- Magic number/string: 7
- Your main loop can be simplified by using a do-while-loop. You don't need `replay` if you do that. Try rewriting it to make sure you know how to do it in the upcoming quizzes. If you need help, don't be afraid to ask :)

• Miko

Hello and greetings from Finland! Thank you for all the amazing lessons on this site. I've been going through these lessons for a week now and what a ride it has been. Probably the best free curriculum on anything I've ever stumbled upon.

Here's my attempt on the second quiz question. All comments and suggestions will be highly appreciated.

constants.h :

user_input.hpp :

main.cpp :

user_input.cpp

• nascardriver

Hi!

- user_input.hpp doesn't need <stdio.h>. Include only what you need.
- main.cpp:34 is always true, because of the checks before that. I suggest doing the error handling first (guess < 0), then, in a new if-statement, compare the input to `rand`. - `main::loop` only has 2 possible value (0 and 1), it should be a `bool`. When you do that, you probably see that a do-while loop is better for this job. - Your formatting is inconsistent and misleading. Your editor probably has an auto-formatting feature, use that. - You're never using `getChar::loop`. Use a `while (true)` loop instead.

• Miko

Hi again!

- Oops... Well spotted! Xcode includes <stdio.h> automatically on header files if you create them at the same time as a .cpp-file. Still getting used to xcode and IDEs in general.

- Do you mean like:

- Good point that I have overlooked so far. I must start doing that from now on.

- Good point again.

Thanks for the feedback!

• nascardriver

> Do you mean like
yes, but now line 21 is always true. It should be a plain `else`.

• Nexteon

Did Q1 with a different solution. This one was really a headache and stump me for months. I use this site to learn about more than just c++ and coding in general and wanted to thank you for these lessons being free. I use this site to get through the beginning of my data structure course.

• nascardriver

The months were worth it, nice code! Keep it going :)

• Simon

Can i do the 1 with a exit?

• nascardriver

You just did, looks good :D

• User1

Any thoughts on my answer to q2?

• nascardriver

- Inconsistent formatting. Use your editor's auto-formatting feature.
- Mark compile-time constants as `constexpr`.
- Use `bool` for booleans, not 0/1
- Line 58 is not a comparison, but an assignment. Even if it was a comparison, it'd always be `true` because of the conditions above.

The rest looks good, nice avoidance of magic numbers :)

• User1

Thanks for that. I've found the auto-formatting feature now, that'll definitely come in handy!

Am I right in thinking the compile-time constants are my min/max and number of tries?

For the booleans do you mean that it's good practice to use true/false rather than 0/1 for the return value?

And good spot on line 58. Is it better practice to leave it as a comparison to show the reason that text output is used or to just leave it as an else since it will always be true if the other two are false?

Thanks again for all your help, I've been loving these tutorials so far.

• nascardriver

> Am I right in thinking the compile-time constants are my min/max and number of tries?
You are right

> For the booleans do you mean that it's good practice to use true/false rather than 0/1 for the return value?
Yes. You shouldn't use any literal apart from false/true for booleans.

> Is it better practice to leave it as a comparison
No, remove it. For integers, the compiler will probably optimize it away, but for other types this could have a performance impact. If this weren't a comparison, but something that isn't easy to understand, add a comment to the else-part to explain when it happens.

• Dudz

• nascardriver

- Use `bool` for values that have only 2 options.
- Line 76+: Should be a do-while loop with `playAgain()` as the condition.
- Line 72: Unnecessary conditional operator. `operator==` returns a `bool` already.
- Line 43 is always true.

• Dudz

• nascardriver

The formatting of your for-loop is confusing, I suggest using curly braces. The rest looks good :)

• Dudz

Thanks :). For-loop formatting changed.

• yup

This was my answer to the second quiz question. I would love to know how it can be improved!

• nascardriver

- Magic string/number: 7/8
- Avoid recursion (A function calling itself) (game -> playAgain -> game -> ...). Your program will crash after a cerain amount of games. Use a loop.
- Line 46 is always true because of the conditions before that.

Try getting rid of the recursion to make sure you understood loops. The rest looks good :)

• Homero

I made a really different code for question one and wanted to know what could be improved.

main.cpp

• nascardriver

Hi!

- Use double literals for doubles (eg. 0.0 instead of 0)
- Initialize variables instead of assigning to them.
- `sqrt` should be `std::sqrt`. `sqrt` is the C version of the same function.

The rest looks good ::)

• Homero

When you say initialize the variables, are you referring to the ones with the equations or other variables?

• nascardriver

I was referring to `delta`. You initialize it to 0.0 but assign a different value right away. If you know the value of a variable and the point of its definition, initialize the variable.

• Homero

Got it.
Thanks!

• Fabio Henrique

I tried to fix every issue that you pointed
constants.hpp:

main.cpp

Just some questions:
-Is it good or bad to have a const function like my clearInput() ? it seems to work pretty fine as a const.
-And I was trying to remember why did I disallowed 0 and allowed it again after, and it is because of the cin.ignore(), every time it runs on a bad input it transforms the value of guess back to 0 AFAICS, like when a char is input in the guesses... my question is, if we wanted to allow 0 in our gueses, how could we do that and still be able to ignore extraneous input with cin.ignore() ?
-I just declared maxstreamsize as a long because clangd told me that it would evaluate for a long, it can evaluate for something different in some case ?

Thanks

PS: and I knew you probably would react like that, but this formatting is not disgusting for me XD

• nascardriver

You still have magic numbers/strings (Line 10, 11, 15, 19, 84, 104, 105).
Line 107-111: `while (playAgain());`

> Is it good or bad to have a const function like my clearInput() ?
That function returns `void`, you can't assign to a `void` anyway, so the `const` doesn't do anything. For other types, it can catch very rare mistakes, but it prevents an important optimization which you'll learn about later (Move sematics). `const` return values do more bad than good (Unless you're returning a reference/pointer (Covered later)).

> [std::cin] transforms the value of guess back to 0 AFAICS
That's correct. You should use `std::cin.fail()` to check if extraction failed, not the value.

> clangd told me that it would evaluate for a long
Your editor/ide/tool tells you what the type is AFTER preprocessing files. Take this simple example

If you have a big powerful pc, `streamsize` will be `long long`, and clangd will tell you that it is `long long`. But if someone uses your code on another machine, `streamsize` is a `char`. If you have a look at a