6.x — Chapter 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 (in C++11).

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. For-each 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 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 0 (or in C++11, nullptr) 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 they are pointing to is. This means sizeof() and for-each 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, so make sure to check whether new returned a null pointer.

Make sure to use the array delete (delete[]) when deleting an array. Pointers pointing to deallocated memory are called dangling pointers. Dereferencing a dangling pointer can cause bad things to happen.

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 that handles its own memory management and remember their size. These should generally be favored over built-in dynamic arrays.

Quiz time

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 a fixed array to store the number of each item the player is carrying (use built-in fixed arrays, not std::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().

Show Solution

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

For the following input:


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

Hint: You can modify the selection sort algorithm from lesson 6.4 -- Sorting an array using selection sort to sort your dynamic array. If you put this inside its own function, the array should be passed by address (as a pointer).

Show Solution

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

Hint: Use reference parameters

Show Solution

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 a null terminator. Write a main function that tests the function with the string literal “Hello, world!”.

Hint: Use the ++ operator to advance the pointer to the next character.

Show Solution

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


Show Solution


Show Solution


Show Solution


Show Solution


Show Solution

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

6a) 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).

Show Solution

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

Show Solution

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

Show Solution

6d) 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.

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

Show Solution

6e) Write a function named printDeck() that takes the deck as a const reference parameter and prints the values in the deck. Use a for-each loop.

Show Solution

6f) Write a swapCard function that takes two Cards and swaps their values.

Show Solution

6g) Write a function to shuffle the deck of cards called shuffleDeck(). To do this, use a for loop to step through each element of your array. Pick a random number between 1 and 52, and call swapCard with the current card and the card picked at random. Update your main function to shuffle the deck and print out the shuffled deck.

Hint: Review lesson 5.9 -- Random number generation for help with random numbers.
Hint: Don’t forget to call srand() at the top of your main function.
Hint: If you’re using Visual Studio, don’t forget to call rand() once before using rand.

Show Solution

6h) 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

7) 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() that returns true if the player wins, and false if they lose. This function should:
* Accept a shuffled deck of cards as a parameter.
* Initialize a pointer to the first Card named cardPtr. This will be used to deal out cards from the deck (see the hint below).
* Create two integers to hold the player’s and dealer’s total score so far.
* Implement Blackjack as defined above.

Hint: The easiest way to deal cards from the deck is to keep a pointer to the next card in the deck that will be dealt out. Whenever we need to deal a card, we get the value of the current card, and then advance the pointer to point at the next card. This can be done in one operation:

This returns the current card’s value (which can then be added to the player or dealer’s total), and advances cardPtr to the next card.

Also write a main() function that plays a single game of Blackjack.

Show Solution

7a) 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.

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

7b) In actual blackjack, if the player and dealer have the same score, 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
6.16 -- An introduction to std::vector

324 comments to 6.x — Chapter 6 comprehensive quiz

  • ASP

    In Q 5b,
    ptr = &y;
    should be
    *ptr = &y;

  • Trevor

    In the Blackjack challenge, rather than using the three switch statements to look up the value, rank symbol and suit symbol, I went with three const arrays, reducing the function printCard to two active lines and the function getCardValue to a single active line:

    I believe that this would be faster (fewer jumps during code execution) and generate smaller code, so is there a downside - apart from not having array bounds checks in these functions (yet)?
    PS: I declared the arrays outside the functions as they could have use in other parts of the program, and this puts them closer to the enumeration declarations.

    • nascardriver

      Hi Trevor!

      When just looking at the code it's clearer which rank corresponds to which symbol/value when using a switch statement whereas in your case one needs to count the indexes. This could cause trouble when adding/removing new cards. An easy solution is formatting the arrays in a different way.

      This might violate your formatting conventions and won't be readable as good on smaller screen or if the lines get longer.
      That's a minor issue, do what you like, I can't think of any real problems.

      You don't need to state the array size in the square brackets when you initialize an array.

    • Alex

      This approach has upsides and downsides. If you're going for pure performance, direct indexing an array will be faster. However, when debugging, it's useful to have built-in range checking to help catch errors in development. To do that, you'd need to write a function that asserts on the range and then indexes the array. But unless that function get inlined (and it probably won't), that will have a performance impact in production.

      Overall, I think it's an equally valid approach. I'd maybe even favor it slightly, because it allows you to keep all your data tables in one place, which may be more maintainable than a bunch of sequential functions.

  • Vili Sinervä

    Hi! Is there a reason to prefer the solution provided for question 1 or would this be equally good:

  • Vili Sinervä

    Hi! In question 5c could you also pass the array by reference to prevent it from decaying into a pointer? So would this work:

  • xjuggy

    Quick question on #4:

    First of all, I misinterpreted what was meant by "use operator++", reading it as using the postfix "++" (i.e. "x++").

    I did it this way but can it lead to any trouble or is it OK?:

    My understanding is that the "str" pointer is passed on to the dereference operator prior to incrementing.

    • Alex

      > First of all, I misinterpreted what was meant by "use operator++", reading it as using the postfix "++" (i.e. "x++").

      I updated the text to make it clear you should use the ++ operator, not necessarily the postfix version.

      >I did it this way but can it lead to any trouble or is it OK?:

      Yes, this is fine.

      • xjuggy

        Thanks Alex,

        I have to say this site is excellent !

        I've always wanted to learn c++ but have always been reticent due to all the talk of memory management, pointers, references, etc...

        Your site breaks it down into manageable chunks, that while at first it's challenging, eventually it sinks in.

        Furthermore, while the "Do this..." is definitely important, the "Don't do that..." is equally valuable.

        In short, thanks for all the hard work. 🙂

  • Jasmine

    Dear Alex, thank you very much for the excellent tutorial. I really appreciate the time and effort that you have put in to making it so easy to follow, yet very detailed and interesting. I am learning a lot!

    I have some quick questions about Q1 and in general. The code I am referring to is below. Is it acceptable to use references instead of pointers when passing arrays as function parameters? I mean for the purpose of maintaining the array type and allowing use of a for else loop, rather than it decaying into a pointer? Is there any case where/any reasons why you should not do this? If you wanted to swap 'auto' with a type name what would you write? Thank you!

    • nascardriver

      Hi Jasmine!
      "If you wanted to swap ‘auto’ with a type name what would you write?"
      Let's look at this example

      In this case,

      can be replaced with

      Note: You need to specify the array size in the function header which leads us to

      "Is there any case where/any reasons why you should not do this?"
      Let's have a look at another example

      Your compiler will create two countTotalItems functions

      Both of these will have all the code you wrote in the original countTotalItems function. This can lead to huge binaries. (Additionally, a function will be generated for each type you pass (float, double, int, etc.))

      "Is it acceptable to use references instead of pointers when passing arrays as function parameters?"
      If you have a small amount of arrays with fixed sizes you can do this.
      If you have a lot of arrays in different sizes, don't.
      If you don't have a specific reason to use C arrays, use std::array or std::vector

      PS: Please edit your comments instead of deleting and re-posting them

    • Alex

      Nascardriver has a good lengthy answer showing you the explicit syntax for passing an C-style array by reference. And yes, passing an array by reference to preserve the type information is fine. There aren't really any downsides other than the messy syntax.

      However, as you probably discovered, you can't use auto in function parameters (at least as of C++17) -- it won't compile. If you want to have a single function (countTotalItems()) that can take arrays of different size, you'll need to use a template function rather than an auto parameter:

      This will work with a C-style array (or std::array) of any size.

      • nascardriver

        Hi Alex!
        I just wanna note that gcc supports auto in function parameters since C++14.
        This is just an extension to gcc, not a language feature, but the code provided by Jasmine works with gcc.

        • Jasmine

          Hi nascardriver and Alex! Thank you very much for your answers and examples. I understand much better now.

        • Alex

          Interesting, I wasn't aware of that. I suspect this extension will eventually be incorporated into C++ as a shortcut to creating template functions, but who knows when.

          @Jasmine, you should generally strive to avoid compiler-specific extensions if possible, as it means your code won't be compatible with other compilers should you wish to port to other systems later.

  • Pas

    Hi Alex,

    Thank you for the lessons!
    I have a question with regards to question 7B and the code that needs to be changed in your solution to question 7 in the playBlackjack function.
    I am assuming the "1" in the while loop in line 157 ( for the Q7 solution) is the return value for the playBlackjack function. Is that right?
    What do I need to change this when I use the new enumerator which includes the tie option, I tried changing line 157 to " while (BLACKJACK_PLAYER_WIN) " without success.
    I also changed return true and return false values to BLACKJACK_PLAYER_WIN and BLACKJACJ_DEALER_WIN.
    What needs to be changed in the main function? I added if statements to account for the three options.

    Thank you for your help!

    • nascardriver

      Hi Pas!
      A while loop expects a bool. As long as this bool is true the while loop will continue to run (or stop when break; is executed).

      I have the feeling you skipped a couple of lessons or forgot about their content, I suggest you reviewing Chapter 5.
      In addition to changing the return values to BLACKJACK_PLAYER_WIN and BLACKJACK_DEALER_WIN and modifying main as you described you need to check if playerTotal is equal to dealerTotal in line 178 and return tie if that's the case.

      • Pas


        I believe I have fixed the while loop, but I am having trouble exiting out of play blackjack function.
        The following is my playjack and main function, would you be able to tell me what is wrong?
        I believe the problem lies in exiting the function, as I am not able to exit out of the program.

        • nascardriver

          What do you mean by "exiting out of play blackjack function"?

          Don't use 'using namespace'
          Line 26: You don't need that, the while loop will stop once it reaches break;

      • Alex

        I see "while (1)" a lot in practice because it's easier to type than "while (true)" and both are equally intelligible.

        That said, I've updated the code to use while (true) since this is probably slightly more comprehensible for learners.

  • MyName


    Made my first program, could make it a bit shorter if myChip variable was global and used more separate functions as you advised before.
    Probably can make it much shorter, but don't know how yet.
    Please try it, if you have a bit of time and give some review if this is any good and how to make it shorter.

  • Serge B

    Hello Alex,

    on 6d) 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.

    I’ve tried to call a function to initialize the array with this code:

    The same code works when placed in the main but not in a function. Do I have to overload the operator [] and if so, why?

    Thank you!
    Happy new year!

    • nascardriver

      Hi Serge B!
      Your initializeArray function is taking a Card reference as parameter but you’re passing an std::array<Card> as argument. You’re then trying to call the operator[] on the Card type.

  • Matias

    Here's how I decided to solve for the Blackjack quiz, any improvements you can think of sharing?

    (Besides the last if/else statement for the return I guess :p)

    Thanks for the great tutorials!

    EDIT: I deeply apologize for the poor formatting, I'm using Emacs 🙁

  • Mates

    Hello Alex,
    regarding the Blackjack quiz, how do aces count for the dealer? He is supposed to draw until having at least seventeen, but his hand can have more than one value at the time with the ace.
    Thanks for the tutorials btw.

    • Alex

      It says in the instructions we'll count aces as 11 for simplicity. Keep in mind this implementation doesn't keep track of what cards were drawn -- just the sum of the values.

      In a real blackjack implementation, you'd want to actually keep track of all the individual cards dealt (so you could handle things like doubling down properly) -- but this adds a lot of complexity.

  • Nicolas

    Hey Alex, I thought I'd make the Blackjack game in a way that you can see what card-suits get dealt. First I made two dynamic arrays to store the hand of the dealer and the player. Then I made functions to  deal cards to the hand and print it (I changed the printCard() function to return a string). The only problem I'm having is that, the pointer in dealHand() doesnt stay incremented after the function gets called, so the player and the dealer are dealt the same cards. How do I make it stay changed? I tried making it static or using a reference, which im not sure can be done with a pointer.
    Help and any other feedback regarding the code would be appreciated, thanks.

    • Alex

      Yep, I see the problem. This is covered in a little more detail next chapter, but let me answer quickly here. You know when you pass an argument to a function by value, the function can change the value and the argument won't be changed (because the parameter is a copy of the argument)? Pointers work the same way. If the function changes the value of a pointer argument (its address), you're actually changing a copy of the pointer, not the actual pointer passed in.

      If you want a function to be able to change the address of a pointer argument, you need to pass the pointer by reference.

  • Gaurav

    My code is crashing at line 20 where I am trying to initialize name by user entered name. It seems vector is going out of range. Please help me in figure out the problem and reason behind it. Here is the code:

    • Alex

      std::vector access functions don't resize the vector. So when you access, the assumption is that element i already exists. If it doesn't, you'll get an out of range error.

      In this case, you're better off using the push_back member function to add a new name, as that will cause the vector to get larger if needed. We talk about this more in chapter 7.

  • Kyle S

    5b solution - you don't have information on how to fix it.  In general, I find your material very clear, but I've found this quiz to be very difficult to interpret the expectations and the answers you provide.

  • Michael

    Hi Alex,
    In 5) d)

    Suppose temp is not destroyed(memory freed up) when out of the block. Then temp is still considered in scope right? Since we have a pointer that points to temp which grants us access to it, and according to the definition, scope means where a variable is accessible.

    So is the duration of a variable related to whether its memory is freed up and the scope of a variable related to whether we still have access to that memory address?


    • Alex

      See this lesson for a reminder of the definitions of scope and duration.

      A better example would be this:

      Variable array is a local variable with local scope and automatic duration. Hence, it gets destroyed at the end of the function. However, the allocated memory itself has dynamic duration and isn't destroyed until it's manually deleted by the programmer.

      • Rex Lucas

        Hi Alex

        I understand that using dynamic memory allocation is the way to handle the fact that length is not a compile-time constant.

        However, I am not sure I understand your other comment in 5) d): "Variable temp will also go out of scope at the end of the function, so the return value will be pointing to something invalid". For a fixed length, surely the code below would work, wouldn't it?:

        • Alex

          Nope. Array temp is a local variable, so it will go out of scope at the end of allocateArray(), and the returned address will be invalid.

          • Rex Lucas

            Hi Alex
            Thanks for this clarification. So whereas you can return (for example) an int from a function, you cannot return a pointer from a function.
            I couldn’t find any reference to this fact in your previous tutorials. Maybe its a subtlety of pointer behaviour I still don't grasp - or maybe I just have to take it for granted!

            • Rex Lucas

              Ah ha - I see all is explained in "7.4a — Returning values by value, reference, and address"!!
              Thanks Alex!

            • Alex

              For other readers with the same question: You CAN return a pointer (or reference) from a function (and there are valid reasons for doing so). You just have to make sure that whatever that pointer is pointing at isn't destroyed when the function returns (in other words, that object has to exist outside the scope of the function doing the returning).

              For example, if you pass a value (e.g. a struct variable) to a function by pointer or reference, you can return that same value by pointer or reference back to the caller. Because that object exists outside the scope of the function, it won't be destroyed when the function exits.

              We'll see lots of examples of this in chapter 8 and 9.

  • liuchen

    Hi,Alex! In the following program,I don't understand why the result of "sizeof(string)" is 4 in the printCh function.
    void printCh(char string[])
        std::cout << sizeof(string) << "\n";
        std::cout << sizeof(string[0]) << "\n";

    int main()
        char string[] = "hello world";
        std::cout << sizeof(string) << "\n";
        std::cout << sizeof(string[0]) << "\n";

        unsigned int x = 2;
        std::cout << sizeof(x) << "\n";

        return 0;
    The result is:

  • Kyo

    Hi Alex,
    First time i'm posting here, so wanted to thank you guys for this amazing website that teaches me much more than my school teachers do (french school ftw).

    Question is about the code i wrote for 7 a), modification for the ace value (getCardValue is the same function as in the solution) :

    This goes into my do..while that draws the cards when player hits, and issues the following warning : "value computed is not used [-Wunused-value]" on *cardPtr++.
    However, this snippet still seem to do what I want it to do... Should I ignore this warning ?

    Thank you again.

    • Kyo

      Sorry for the useless message (except for the thanks), I found the solution. I should have tried Stack Overflow before asking here.
      But hey, at least I inaugurated the 5th page.

      For anyone encountering the same warning :

      *cardPtr++ is the same as *(cardPtr++), it evaluates the increment first then dereferences it, so it gets the value the pointer points to (after being incremented) but does not use it. Hence the warning.

      TL;DR : cardPtr++ ftw.

      • Kyo

        Actually I need to edit what I said because it caused my own confusion and may cause confusion to other people trying hard to understand what's happening.

        "so it gets the value the pointer points to (after being incremented)" <- WRONG, because apparently the post-increment operator, despite having a higher precedence than the dereference operator, "binds more tightly" (don't ask me, Stack Overflow said so), which means dereference will happen BEFORE cardPtr is incremented. But it is still the pointer that gets incremented, NOT the value it's pointing to.

        So that is why getCardValue(*cardPtr++) works and actually DOES read the current card's value and not the next's.

        Would definitely like to have your insight on this, Alex.

        (Since that's way too many messages, please feel free to delete any or all of them if necessary...)

        • Alex

          If you look at, post-increment does take priority over the dereference. So the post-increment gets processed first.

          So with getCardValue(*cardPtr++), cardPtr++ gets executed first, which increments cardPtr, BUT because this is a post-increment evaluates to the pre-incremented version of cardPtr. This pre-incremented version gets dereferenced, so we get the current card value.

          Similarly, *cardPtr++ post-increments cardPtr and evaluates to the pre-increment version of cardPtr, which then gets dereferenced. Because the dereferenced value is not used, the compiler generates a warning. So, because the dereferenced value is not used, this expression is equivalent to cardPtr++.

Leave a Comment

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