Search

6.x — Chapter P.6 comprehensive quiz

Words of encouragement

Congratulations on reaching the end of the longest chapter in the tutorials! Unless you have previous programming experience, this chapter was probably the most challenging one so far. If you made it this far, you’re doing great!

The good news is that the next chapter is easy in comparison. And in the chapter beyond that, we reach the heart of the tutorials: Object-oriented programming!

Chapter summary

Arrays allow us to store and access many variables of the same type through a single identifier. Array elements can be accessed using the subscript operator ([]). Be careful not to index an array out of the array’s range. Arrays can be initialized using an initializer list or uniform initialization.

Fixed arrays must have a length that is set at compile time. Fixed arrays will usually decay into a pointer when evaluated or passed to a function.

Loops can be used to iterate through an array. Beware of off-by-one errors, so you don’t iterate off the end of your array. Range-based for-loops are useful when the array hasn’t decayed into a pointer.

Arrays can be made multidimensional by using multiple indices.

Arrays can be used to do C-style strings. You should generally avoid these and use std::string_view and std::string instead.

Pointers are variables that store the memory address of (point at) another variable. The address-of operator (&) can be used to get the address of a variable. The dereference operator (*) can be used to get the value that a pointer points at.

A null pointer is a pointer that is not pointing at anything. Pointers can be made null by initializing or assigning the value nullptr (before in C++11, 0) to them. Avoid the NULL macro. Dereferencing a null pointer can cause bad things to happen. Deleting a null pointer is okay (it doesn’t do anything).

A pointer to an array doesn’t know how large the array it is pointing to is. This means sizeof() and range-based for-loops won’t work.

The new and delete operators can be used to dynamically allocate memory for a pointer variable or array. Although it’s unlikely to happen, operator new can fail if the operating system runs out of memory. If you’re writing software for a memory-limited system, make sure to check if new was successful.

Make sure to use the array delete (delete[]) when deleting an array. Pointers pointing to deallocated memory are called dangling pointers. Using the wrong delete, or dereferencing a dangling pointer causes undefined behavior.

Failing to delete dynamically allocated memory can result in memory leaks when the last pointer to that memory goes out of scope.

Normal variables are allocated from limited memory called the stack. Dynamically allocated variables are allocated from a general pool of memory called the heap.

A pointer to a const value treats the value it is pointing to as const.

A const pointer is a pointer whose value can not be changed after initialization.

A reference is an alias to another variable. References are declared using an ampersand (&), but this does not mean address-of in this context. References are implicitly const -- they must be initialized with a value, and a new value can not be assigned to them. References can be used to prevent copies from being made when passing data to or from a function.

The member selection operator (->) can be used to select a member from a pointer to a struct. It combines both a dereference and normal member access (.).

Void pointers are pointers that can point to any type of data. They can not be dereferenced directly. You can use static_cast to convert them back to their original pointer type. It’s up to you to remember what type they originally were.

Pointers to pointers allow us to create a pointer that points to another pointer.

std::array provides all of the functionality of C++ built-in arrays (and more) in a form that won’t decay into a pointer. These should generally be preferred over built-in fixed arrays.

std::vector provides dynamic array functionality, handles its own memory management and remembers its size. These should generally be favored over built-in dynamic arrays.

Thanks to iterators, we don’t have to know how a container is implemented to loop through its elements.

The algorithms library helps us to save a lot of time by providing many off-the-shelf functions. In combination with iterators (and later lambdas), the algorithms library is an important part of C++.

Quiz time

To make the quizzes a little easier, we have to introduce a couple of new algorithms.

std::reduce applies a function, by default the + operator, to all elements in a list, resulting in a single value. When we use the + operator, the result is the sum of all elements in the list. Note that there’s also std::accumulate. std::accumulate cannot be parallelized, because it applies the function left-to-right. std::reduce segments the list, which means that the function is applied in an unknown order, allowing the operation to be parallelized. If we want to sum up a list, we don’t care about the order and we use std::reduce.

Author's note

std::reduce is currently not fully implemented in all major standard libraries. If it doesn’t work for you, fall back to std::accumulate.

std::shuffle takes a list and randomly re-orders its elements.

Possible output

10
10
2 1 4 3

Question #1


Pretend you’re writing a game where the player can hold 3 types of items: health potions, torches, and arrows. Create an enum to identify the different types of items, and an std::array to store the number of each item the player is carrying (The enumerators are used as indexes of the array). The player should start with 2 health potions, 5 torches, and 10 arrows. Write a function called countTotalItems() that returns how many items the player has in total. Have your main() function print the output of countTotalItems() as well as the number of torches.

Show Solution

Question #2


Write the following program: Create a struct that holds a student’s first name and grade (on a scale of 0-100). Ask the user how many students they want to enter. Create a std::vector to hold all of the students. Then prompt the user for each name and grade. Once the user has entered all the names and grade pairs, sort the list by grade (highest first). Then print all the names and grades in sorted order.

For the following input:

Joe
82
Terry
73
Ralph
4
Alex
94
Mark
88

The output should look like this:

Alex got a grade of 94
Mark got a grade of 88
Joe got a grade of 82
Terry got a grade of 73
Ralph got a grade of 4

You can assume that names don’t contain spaces and that that input extraction doesn’t fail.

Show Solution

Question #3


Write your own function to swap the value of two integer variables. Write a main() function to test it.

Show Hint

Show Solution

Question #4


Write a function to print a C-style string character by character. Use a pointer to step through each character of the string and print that character. Stop when you hit the null terminator. Write a main function that tests the function with the string literal “Hello, world!”.

Show Hint

Show Solution

Question #5


What’s wrong with each of these snippets, and how would you fix it?

a)

Show Solution

b)

Show Solution

c)

Show Solution

d)

Show Solution

e)

Show Solution

Question #6


Let’s pretend we’re writing a card game.

a) A deck of cards has 52 unique cards (13 card ranks of 4 suits). Create enumerations for the card ranks (2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace) and suits (clubs, diamonds, hearts, spades). Those enumerators will not be used to index arrays.

Show Solution

b) Each card will be represented by a struct named Card that contains a rank and a suit. Create the struct.

Show Solution

c) Create a printCard() function that takes a const Card reference as a parameter and prints the card rank and suit as a 2-letter code (e.g. the jack of spades would print as JS).

Show Hint

Show Solution

d) A deck of cards has 52 cards. Create an array (using std::array) to represent the deck of cards, and initialize it with one of each card. Do this in a function named createDeck and call createDeck from main. createDeck should return the deck to main.

Hint: Use static_cast if you need to convert an integer into an enumerated type.

Show Solution

e) Write a function named printDeck() that takes the deck as a const reference parameter and prints the cards in the deck. Use a range-based for-loop. When you can printDeck with the deck you generated in the previous task, the output should be

2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC AC 2D 3D 4D 5D 6D 7D 8D 9D TD JD QD KD AD 2H 3H 4H 5H 6H 7H 8H 9H TH JH QH KH AH 2S 3S 4S 5S 6S 7S 8S 9S TS JS QS KS AS

If you used different characters, that’s fine too.

Show Solution

f) Write a function named shuffleDeck to shuffle the deck of cards using std::shuffle. Update your main function to shuffle the deck and print out the shuffled deck.

Reminder: Only seed your random number generator once.

Show Solution

g) Write a function named getCardValue() that returns the value of a Card (e.g. a 2 is worth 2, a ten, jack, queen, or king is worth 10. Assume an Ace is worth 11).

Show Solution

Question #7


a) Alright, challenge time! Let’s write a simplified version of Blackjack. If you’re not already familiar with Blackjack, the Wikipedia article for Blackjack has a summary.

Here are the rules for our version of Blackjack:

  • The dealer gets one card to start (in real life, the dealer gets two, but one is face down so it doesn’t matter at this point).
  • The player gets two cards to start.
  • The player goes first.
  • A player can repeatedly “hit” or “stand”.
  • If the player “stands”, their turn is over, and their score is calculated based on the cards they have been dealt.
  • If the player “hits”, they get another card and the value of that card is added to their total score.
  • An ace normally counts as a 1 or an 11 (whichever is better for the total score). For simplicity, we’ll count it as an 11 here.
  • If the player goes over a score of 21, they bust and lose immediately.
  • The dealer goes after the player.
  • The dealer repeatedly draws until they reach a score of 17 or more, at which point they stand.
  • If the dealer goes over a score of 21, they bust and the player wins immediately.
  • Otherwise, if the player has a higher score than the dealer, the player wins. Otherwise, the player loses (we’ll consider ties as dealer wins for simplicity).

In our simplified version of Blackjack, we’re not going to keep track of which specific cards the player and the dealer have been dealt. We’ll only track the sum of the values of the cards they have been dealt for the player and dealer. This keeps things simpler.

Start with the code you wrote in quiz #6. Create a function named playBlackjack(). This function should:

  • Accept a shuffled deck of cards as a parameter.
  • Implement Blackjack as defined above.
  • Returns true if the player won, and false if they lost.

Also write a main() function to play a single game of Blackjack.

Show Solution

b) Extra credit: Critical thinking time: Describe how you could modify the above program to handle the case where aces can be equal to 1 or 11.

It’s important to note that we’re only keeping track of the sum of the cards, not which specific cards the user has.

Show Solution

c) In actual blackjack, if the player and dealer have the same score (and the player has not gone bust), the result is a tie and neither wins. Describe how you’d modify the above program to account for this.

Show Solution


7.1 -- Function parameters and arguments
Index
6.18 -- Introduction to standard library algorithms

967 comments to 6.x — Chapter P.6 comprehensive quiz

  • Ayushman

    Thanks for the awesome tutorial, am really grateful that someone is making and updating a tutorial of this extent.
    I had a issue while solving this exercise:

    In the main function my compiler tells me deck[] subscript requires array or pointer type.
    C2109    subscript requires array or pointer type    Comprehencive       location here....Ex6\ComprehenciveEx6.cpp    123

    • nascardriver

      Hi!

      You have two variables called "deck". The one with the closest scope will be used, which in line 121, is `int deck` from line 117.

      - Enable compiler warnings. Line 62: '10' is not a single character.
      - Initialize your variables with brace initialization.
      - Use ++prefix unless you need postfix++.
      - You're using `std::array` all over the place, add a `using` alias.
      - Use `std::srand`, `std::rand` and `std::time` instead of their global-namespace counterparts. (This is also wrong in the lesson, so it's not your fault.)
      - `std::time` wants a pointer, pass `nullptr`.
      - Line 99: Magic number: 51

      • Ayushman Singh

        -I changed the variable names to not cause the conflict again.
        -The magic number has been commented to the code.
        - Am working on other habits.

        I still have a query why did the error come out as subscript requires array or pointer type when it is supposed to be the index of std::array which takes size_type as the index?

  • Connor

    Solution to #2. All feedback is welcome :) Thanks in advance!

  • zwaffel

    Hey thanks for making all these fun exercises. Though i have been scratching my head for the past hour trying to figure out why this wouldn't compile.

    Turns out the error was here

    Im not sure why but i have to specifically say its an struct otherwise he tries to convert it to an int.

    How does this happen in the solution you dont have this and im sure the sollution you posted is working. Using visual studio 2019 the errors i was getting are

    code]Severity Code Description Project File Line Suppression State Suppression State

    Error    C4430    missing type specifier - int assumed. Note: C++ does not support default-int    calculator    C:\Users\sieme\c++ projects\calculator\calculator\Main.cpp    7        
    Severity Code Description Project    File Line Suppression State Suppression State

    Error C2143 syntax error: missing ',' before '&' calculator C:\Users\sieme\c++ projects\calculator\calculator\Main.cpp    7        
    Severity Code Description Project File Line Suppression State Suppression State

    Error C2664 'void printCard(const int)': cannot convert argument 1 from 'Card' to 'const int' calculator C:\Users\sieme\c++ projects\calculator\calculator\Main.cpp    44[/code]

    • nascardriver

      Hi!

      In line 1, there is nothing called `Card`. You can add a forward declaration of `Card` and remove the `struct` from the function declaration.

  • Cypeace

    Hey guys!

    I'm having really good time solving the quizzes. Just finished with 2) and there's one thing I don't quite understand..
    It's when I get to initialize an array for the struct that I did different and yet it worked so far to produce the output.
    What exactly did I do there? :D

    Other than that I managed to get very close to your solution, of course I will make separate functions later ;-)

    Thank you for your assistance!

    • nascardriver

      > what exactly is this statement?
      It's not C++ is what it is. Make sure you followed lesson 0.10 and disabled compiler extensions. Those settings are per-project. You need to set them every time you create a project or create a template with those settings.

      - Don't use `std::endl` unless you need to. Use '\n' instead.

      Your code looks good otherwise, keep it up!

  • Pave

    Thanks! This quiz was amazing. I first tought the blackjack game would be too difficult, but then i managed to do it without looking at the answers. I'm happy that i learned from these tutorials.

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    I have a problem. This is my code.

    When I run it, i got an error: "Process terminated with status -1073741510". Every time I call insertCards, my program is crash. I don't know why because in past I call this function and it works perfectly, but know I try again and I got this error. Any idea?

    • nascardriver

      Use your debugger to see where exactly it crashes. I suspect `card` leaves the valid range of `cards`, inspect the values when the debugger stops the program as it crashes.

      • Samira Ferdi

        Hi, Nascardriver! Thanks for reply!

        I use debugger and it leads me to find the error (thanks for your suggestion). Yes, your right. It's about valid range! The function above is right. The problem is my CardRank enum:

  • Daniel

    I am quite proud of this solution. I used another source for the throw.

    • nascardriver

      Hi Daniel!

      The enum should've been used to index the array. Right now you have magic numbers in line 12+ and it's not obvious to the caller of `changeItemQuantity` which values of `item` are valid.

      - Avoid global variables (`iPotDeviation` etc.).
      - Line 26, 27 is not valid C++. You can't create a static array with a non-const size. Make sure you followed lesson 0.10.
      - Initialize your variables with brace initializers.
      - Use ++prefix unless you need postfix++.
      - Use single quotation marks for characters.

  • Wallace

    Minor typo: "A pointer to an array doesn’t know how large the array they are pointing to is" should probably be "A pointer to an array doesn’t know how large the array it is pointing to is" or perhaps rewritten as "A pointer to an array doesn't know how large that array is."

  • josiah_wi

    Here's my solution to #2.

    student.h:

    and main.cpp:

    -Josiah

    • - Explicitly initialize your variables if you use their initial value.
      - Inconsistent formatting. Use your editor's auto-formatting feature.
      - `getStudents` can extract directly into the student, you don't need separate variables.

      - `printStudents::students` should be `const`, you don't modify it.
      - Line 42+ would be easier to read with a different name than `j` or by iterating over indexes rather than pointers.

      • josiah_wi

        Thank you! I will update my code and remember to check for these things in future exercises. I am not sure where I have inconsistent formatting, other than an extra space on line 16 that shouldn't be there, but there might be some; I am that weird guy that writes with SciTE and Mousepad and builds it as a cmake project.

        -Josiah

        • > not sure where I have inconsistent formatting
          The space in line 16.
          Asterisk/Ampersand at the type vs at the name (Line 67 vs Line 35).

          > I am that weird guy
          ((Text editor + CMake) > IDE) all day long. Wait until you have to compile something on a remote machine and you're the only one not lost without an IDE.

  • josiah_wi

    Hi, I'd like to thank you guys for this tutorial, working through it has been amazing so far, and the concepts are presented very well. I turned all the warnings on since day 1, as recommended in the introduction, and I have -Werror turned on as well. While solving quiz #2 today I came across a warning that I do not have the knowledge to circumvent, and your solution code triggers the same warning. The warning/error is "error: ‘Student::name’ should be initialized in the member initialization list [-Werror=effc++]
    struct Student". I have tracked it down and I believe the culprit is this line:

    . What can I do about this?

    -Josiah

    • That warning is wrong, it's irrelevant to structs. Use clang++ instead of g++, this won't be the last issue you have with g++.

      • josiah_wi

        The warning may be unnecessary, I wouldn't say it's irrelevant though. It was explained to me that new calls constructors for the objects it is creating, and the warning was complaining that there were variables not initialized in the constructor. I worked around the warning by setting the struct members to zero-initialize, like so:

        The drawback is that zero-initializing large data structures in an array is expensive, but new initializes them either way as far as I know, please correct me if I'm wrong about that.

        -Josiah

        • I said it's irrelevant, because initializing something in the member initializer list implies a constructor, but structs shouldn't have constructors. If you fixed it by doing what the warning says, you'd write poor code.

          > new calls constructors for the objects it is creating
          Not necessarily. You didn't explicitly initialize the array by means of

          If those braces are there, everything is fine. Without them, the array elements are default-initialized. `name` is a class-type (`std::string`), so its constructor is called and everything is nice. `grade` is a fundamental type (`int`), it won't be initialized to a specific value, reading from it causes undefined behavior.

          The safest solution is your's, initialize the members at their declaration.

  • Alexander S.

    How is this for Quiz #1?

    • - Initialize your variables with brace initializers.
      - Limit your lines to 80 characters in length for better readability.
      - Don't set enumerator values unless you use them.
      - `totalItems::player` should be `const`.
      - `LOG::player` should be `const`.
      - Line 28+: You're not using `index` for anything. Remove `cycle` and use `index`.

      Have a look at the solution to see how this can be done with a 1dimensional array.

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    This my quiz no 6 so far! What do you think?

    1. This is card.h

    2. This is cardfunctions.h

    3. This is printcard.cpp

    4. This is my insertcard.cpp

    5. This is printdeckofcard.cpp

    6. And this is my swapcard.cpp (actually this is redundant because I can use std::swap instead)

    7. This is my program

    • Hi!

      1.
      Remove `MyCard`. It's the same as `Card` but less usable. (Ok, I see what you're using it for, but that doesn't help a lot. If each card has a unique identifier, you don't need a list.)
      > The alternative
      Identifiers starting with an underscore (_) are reserved names. Don't use them.

      2.
      You're now using "MyCard" for 2 different things (Namespace vs Parameter).
      Yes, include "card.h". Your code only compiles because every file that uses "cardfunctions.h" includes "card.h" first. Your includes should be independent of their order.
      Use a global type alias for `std::array<Card, 52>`.

      3.
      Use single quotation marks for characters.

      You don't need to create a .cpp for every function. It's fine to define all functions of one header in the same .cpp file.
      The rest looks good!

      • Samira Ferdi

        Thank you very much, Nascardriver!

        So, these are my changes:

        1. card.h

        2. cardfunction.h

        3.cardfunctions.cpp (I move my functions here)

        • > Should I define card_t once again here?
          No, you already have access to it through "cardfunctions.h". Use it in line 76.

          > My program run fine if I don't include this. Should I?
          Yes. If you use something, include its header.

          • Samira Ferdi

            Thank you, Nascardriver!
            So, is like this?

            So, for cardfunctions.cpp, it's like I should #include<string> (if I use std::string) although <string> header define in <iostream>?

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    how to make empty std::array? I have a problem about it.

    The result is:
    00 00 00 00 20 00 20 00 00 0C 20 00 4C
    00 00 00 2C 00 2C 20 2C 00 00 00 20 00
    and so on and so forth...
    The point is the result is not empty(in this context I mean 00)

    This is my printDeckOfCards()

    And this is my printCard()

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    Alex, you recommended that struct should be passed by reference and built-in array should be passed by address. How I passed built-in array that has type struct?

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    This is my code for quiz no.2 (minus sorting). What do you think?

  • Samira Ferdi

    Hi, Alex and Nascardriver!

    I wanna ask you about the compiler complain about unitialized struct member, so, I should do this instead uninitialized struct members. Is it okay?

    But, if I do this, my program runs fine and compiler throw error if I initialized the struct member. Why this happen?

    My second question is, what is the consideration about accessing struct member using reference or pointer if struct passed into function?

    My last question is, how is the way passing struct by pointer? My code below is not run

    • > Is it okay?
      Yes, initialize struct members. Line 3 should use empty curly braces.

      Post your compiler's error messages.

      • Samira Ferdi

        Hi, Nascardriver! This is for my first question above!
        This is when I got (compiler's error message) when I just initialized my struct members (this is just the only change, and all others is still the same).But, if I don't initialized my struct members, this program above runs fine (with no any errors and warnings)

  • Sam

    Solution for question #2