Search

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:

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

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 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?

a)

Show Solution

b)

Show Solution

c)

Show Solution

d)

Show Solution

e)

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
Index
6.16 -- An introduction to std::vector

261 comments to 6.x — Chapter 6 comprehensive quiz

  • JRCS

    When I was younger, we had an old Amstrad machine that came with a book of programmes you could type in. I had no idea what any of the stuff meant, but I happily typed away at it anyway.

    One of the main ones was a programme for this very game. While I can’t recall how it was written, or even in which language, I am happy to now say that I don’t need that book anymore.

    The following is about twice the size of your solution, but it works for the most part, so I’m happy.

  • John Halfyard

    Alex,

    I came across a glitch (in my own code I mean), where in the printCard(const Card &card) function, I used "10" instead of "T" (see below).  Why does this card ‘freak’ out when you try to print it?

    • Alex

      Putting more than one character inside single quotes makes it a multicharacter literal, and multicharacter literals are handled in an implementation-specific way. That is to say, your compiler can decide to do whatever it thinks makes sense. In short, you should avoid multicharacter literals altogether, because they do not behave consistently across all compilers and platforms.

  • John Halfyard

    Hate peaking at the solutions when I’m stuck.  But the idea for Q2 two with the Struct - are we only supposed to have one array for the names and the ages come along for the ride?  How do you apply the user input to the Struct?  So far I have the following:

    • Alex

      You’re supposed to have one array where each element is a Student. The Student struct contains the name and grade bundled together. So you only need one array total (holding Students), not separate arrays for the names and grades.

      Then you can access the name via array[index].name and the grade via array[index].grade.

  • CrazyL

    Here is the upgrade to Quiz 6h). This one took some thinking, especially since I didn’t want to implement some "ace stack" or something similar. All it took in the end were two bools:

    ~ cardGame.cpp ~ (changes only)

    • Alex

      Good thinking -- though this solution only works for a single ace.

      • CrazyL

        @Alex

        "[..] though this solution only works for a single ace."

        You’re right of course, but I don’t think that’s a problem in this special case: The game ends if a player has more than 21 points, that’s why any player can have only one soft ace at any time. Two soft aces would add up to 22 points => the second one would only count as 1Pt anyway and would not be pushed to the "soft ace stack", while the first ace simply stays on the stack.

        If I understand the rules right, there is no way that more than one ace is pushed to the "soft ace stack" per player at any given time => Only one bool needed to test: "Stack has one item" or "stack is empty"!

        • Alex

          Oh, I see! I mixed up what you meant by soft and hard, and misread your code. I think you’re right. Great insight on your part, and clever solution.

  • CrazyL

    Hello Alex,

    I’d say the two extra questions 6h), 6i) are misnamed, because they assume you already finished 7) -- that’s why they’d better be 7a), 7b), or am I mistaken?

    Anyway, the quiz itself was great -- the task is big enough that you feel the need to structure the code though it’s still managable. Thank you for this tutorial!

    P.S.: After I deleted a message, my next comment got rejected by a "duplicate detected" message. Weird…

    Here is my solution to 7):
    ~ main.cpp ~

    ~ cardGame.h ~ (just forward declarations of most functions in cardGame.cpp)
    ~ cardGame.cpp ~

    ~ cardTypes.h ~ (only a snippet, the other types are essentially copies of Alex’ solution)

  • codenoob

    Hey!

    A small question on the first quiz. 🙂

    Your example has:

    I did:

    And it seems to work. I have been a bit confused for the past few chapters about pointers etc and I will have to reread a few more times I think. But I gotta ask what’s the difference between these lines. You have a * operator there and I don’t.

    Here’s the rest of my program if you need to see it to answer:

    • Alex

      Both * and [] in a function parameter tells the compiler to expect a pointer value, so they are identical. Semantically, some programmers like to use [] when passing an array and * when passing a single value. Others feel you should always use * since the array isn’t treated the same as a fixed array. Which you use is up to you.

  • Eric

    Hi Alex, you made function:

    int getRandomNumber(int min, int max)
    {
        static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0);
        return static_cast<int>(rand() * fraction * (max - min + 1) + min);
    }

    What is diffrence between upper code and lower code?(if we write in getRandomNumber(0,51);)

    int swapIndex = rand() % 52;

    What is fraction(in code)?
    And not related question:what is std::array<type> and where can i found something about it?
    Maybe there is answer in chapter 5 random numbers but i didnt found it or understand it.
    Thanks

    • Alex

      Because RAND_MAX isn’t evenly divisible by 52, lower numbers will appear slightly more often than higher numbers if you do this. This code also doesn’t account for a non-zero min.

      The function provided gives a more even distribution of numbers, where low numbers will appear with the same probability as high numbers. rand() * fraction converts the result of rand() into a floating point number between 0 and 1. The rest of the function maps this unit range to the range of [min, max] evenly.

      std::array is discussed in chapter 6.15.

  • Dan

    Is there any purpose to using an enum in problem 1 besides misdirection?  I wasted a bit of time trying to figure out what to do with the enumerated items before I realized that there is nothing to do with them.

    • Alex

      They document the meaning of the elements in the array. If you extended this program any further, you’d probably want them to be explicitly defined.

  • Aditya Pratap

    Hi Alex,my compiler showed an error " expected a ‘;’ " in line 25 why did that happen?

  • umang

    In solution to ques 7 , getCardValue() function has a card reference parameter . So how is it possible to pass a pointer value to it?

    dealerTotal += getCardValue(*cardPtr++);

    • Alex

      We’re not passing a pointer to it. *cardPtr dereferences cardPtr to get the card, which is passed to the function. Then the postfix ++ advances the pointer to the next card.

  • Dear Alex,

    Not for on the board, but can you tell me:

    What is this? Why is it there?
    Plz e-mail…

    • Alex

      It’s a special include that needs to be the first line of your program if you’re using Visual Studio with precompiled headers turned on (which they are by default).

  • ”Arrays can be made multidimensional by using two indexes.”
    Shouldn’t it be ”using multiple indexes”? 😀

  • AMG

    Another option for extra credit (or part of assignment) maybe to distinguish BlackJack (first two cards: ace and any 10) from 21 (any cards combo). Making split will be interesting … 🙂

  • AMG

    Alex,
    Please add to BlackJack description when card deck has to be shuffled: after each game round or until some cards left in the deck. In my version I did it after each round. About extra credit … An ace counts strictly as 1, when a player has score 11 or more. There are some differences in BlackJack. In some casinos when a player has "ace" and "8", dealer may ask player to chose:"9 or 19". Either to stay with 19, or may double bet on 9. Speaking about BlackJack, your mini assignments (shuffle cards, getCardValue(), etc.) simplify the whole task drastically. Extra credit may be given for breaking BlackJack game into "right" functions, the rest is straight forward.

    • Alex

      I’ve added to the quiz description that your code only needs to play one game of blackjack, making the question of when to shuffle (between games or when run out of cards) irrelevant.

      And yes, this program doesn’t account for doubling down, for simplicity.

  • AMG

    Alex,
    Suggestions for BlackJack assignment:
    * Player gets card
    * Dealer gets card
    * Player gets card (if player gets first 2 cards, then this step is skipped)
    * A player can repeatedly “hit” or “stand”. (your text and so on)

    "Create a function named playBlackjack() that returns true if the player wins, and false if they lose." Stand off case is missed here, so playBlackjack() should return 3 different values.

    • Alex

      Yeah, we simplified the game a bit. I added a comment to explicitly note this, and another quiz question asking how we’d modify the program to account for the three result cases.

  • AMG

    For problem 6g) why don’t you use for-each loop? Thanks.

    • Alex

      For-each loops don’t give you an index. We use the index to perform the card swap.

      • AMG

      • AMG

        Here is the snippet with for-each loop.

  • Hello! Coach. I am having trouble with language: What is hit and stand >>"The player can hit or stand"

    Is it to decide to leave the game or stay?

    • Alex

      Nope. Hit and stand are explained in the subsequent lines in the game instructions. I’ve quoted the terms to make them stand out better. Hit means get dealt another card. Stand means stay with what you already have been dealt.

  • Hello! Coach. I don’t understand exercise 3: swap values. I did it that way. I think I am doing it very wrong.

  • :(

    Im stuck in the second one, in the solution, i dont understand how this line:

    interact with:

    how come you cant use Student[index] instead, why students? isnt students a pointer and not an array? i dont understand how arrays and structs interact, how do you call them and when to use the point (.name). Its related to object oriented programming?

    • Alex

      Student is the type name of the elements in the array. students is the name of the array itself.

      declares a dynamic array of Students (named students) of length numStudents.

      outputs the name of the Student in the students array with index number index.

      students is a pointer, but pointers are arrays work similarly in C++. The . operator is the member selection operator. Review the lesson on structs for more info.

  • lnm

    Although I quite don’t understand the blackjack rules, I have done it. Just don’t know if I do right or wrong compared with the standard rule. Please check it for me, and optimize for better performance or better look. Thanks.

    // At first I thought it would be around 100 lines, it came out near 300 line !?

  • Nick

    Hey Alex! Your tutorials are great! I’ve made the Blackjack code as you described in the quiz, and then modified it a bit to include the bonus question and ties.

  • Erik W

    How would I better optimize this code for number 2? I figure I can use references and pointers in more locations.

  • Arun

    Alex,
    For question 6 why do the printCard and printDeck create a ref (&deck and &card)?
    Is it just for performance, or for a different reason?
    Thanks,
    Arun

  • Mr C++

    int* allocateArray(const int length)
    {
        int temp[length];
        return temp;
    }

    In this, How can u say that temp goes out of scope..it is so common we return the value of various variables declared inside a function ! So, Why It is Different for arrays?

  • Mohsen

    Hi Alex.Thank u again for your great tutorial.
    I couldn’t solve quiz no.7 based on your tips. so i tried to do it by another way.
    I googled to find out how can i add an element to std::vector. and i figure it out this can be done with .push_back . I know its kind of messy but i want to know your opinion about it. Thanks

    • Alex

      It’s a little inefficient (since you’re recalculating the total scores) but it gives you the advantage of knowing what the user’s specific cards are. This would probably be necessary if you wanted to implement other blackjack features, such as the ability to double down.

  • Hi, I think there’s a dangling pointer in the solution to Question 2 since you never assign 0 or nullptr to students.
    Thanks as always.

    • Alex

      We assign 0 or nullptr to a deleted pointer only when that pointer is not going out of scope immediately thereafter. Since students is destroyed immediately after deletion (when it goes out of scope) setting it to 0 or nullptr is unnecessary.

  • Chris

    Hey alex,
    i wrote your bonus question into actual code. Here are the important parts :