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 two indexes.

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.

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.
* 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.

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.

Show Solution

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

7.1 -- Function parameters and arguments
Index
6.16 -- An introduction to std::vector

155 comments to 6.x — Chapter 6 comprehensive quiz

  • Avneet

    Closing [/solution] tag is missing in 5e. I will enjoy solving these 🙂

  • Josh

    Thank you so much for adding these quiz questions, they are very helpful.

  • Bene

    Hi Alex, thank you very much for your great tutorials!

    I have a question regarding quiz 4): What exactly is the pointer

    declared in line 8 of your solution needed for?
    Wouldn’t the program behave exactly the same if we used the pointer passed to the function?
    Thanks, Bene 🙂

  • Gopal

    Quiz#5 and question#e: You also missed return 0; at end of main function.

  • Jaq

    For solution 2 if you enter a letter instead of a number for the first prompt the do while loop never ends. I seem to recall a way in which you could avoid this, did you leave this out to simplify the code for the example?

  • Alexandre

    Hi Alex ! Thank for the series. Great work!

    One question…

    At Pointer to Deck, in your solution, you used

    This produced very predictable drawns.(almost always the same)
    I changed it to

    This gives a correct randomness.

    Did i have missed something here ?

    • Alex

      This doesn’t make sense to me. All cardPtr is doing is iterating through the previously shuffled card array. Switching from post-increment to pre-increment should only have the impact of skipping the first card in the deck, not anything to do with how random the results are.

      • Alexandre

        You are right! Maybe i need to take more breaks between the chapters!
        Today i checked the code again and found the problem.
        It was very subtle!

        Thank you again.

  • Wonn Jen

    For the printDeck() function, I origially used a new variable, otherCard, and called swapCard() on both cards. But the deck it returned contained repeated cards. Would you mind explaining why is that so?
    Thanks!

    • Alex

      The goal is to swap two cards, right? So the code I wrote picks a random index, and then swaps the values of deck[i] and deck[otherIndex]. No duplicates introduced.

      Now look at your code:

      The first thing that happens is otherCard becomes a copy of deck[getRandomNumber(0,51)]. So when you do your swapCard, you’re swapping deck[i] with the copy of the value of deck[getRandomNumber(0,51)] instead of the actual random card picked. After your code runs, deck[i] will hold the value of the random card, but the random card never got assigned the value of deck[i] (the copy did instead).

      You could fix this like this”

      Now when you swap deck[i] and otherCard, you’re swapping deck[i] into the actual random card rather than a copy of it.

      Make sense?

  • Lukas

    why can’t I use vector as dynamic array here?:

    Thanks!

    • Alex

      You can. The problem you’re having is that names is a vector of length 0. So when you’re using operator[] to access the array elements, you’re outside of the range of the array.

      All you need to do is add this line jusy beyond where you declare vector names:

  • Mike

    Hi Alex!

    In the solution for quiz #2 you use std::swap(), but do not have <algorithm> nor <utility> included.

    In quiz #6a problem description there’s a missed comma between diamonds and hearts.

    Problem description in quiz #6h was confusing because I didn’t know the rules of the game except for what you’ve explained in quiz #7. My first thoughts were that the players decide to count an ace either 1 or 11 (throughout the game) before they start playing, or that each time you see an ace you should determine whether it’s 1 or 11 according to some randomness, which doesn’t really make any sense. I had to read the rules elsewhere to realize that you can _choose_ to count an ace 1 or 11 (whichever is better for your score). Maybe a bit more detailed explanation would help the unfamiliar with the game.

    Thank you for such a great tutorial!

    • Alex

      Thanks for the feedback. I’ve fixed the syntax issues and clarified the rules around how aces are meant to be handled, and added a link to a summary of the game for those who are unfamiliar with it.

  • Sean Kelly

    Thank you for this great comprehensive quiz!

    It makes me happy on the amount of information I have retained, and gave a chance to really screw around with what we learned.

  • Greg

    Hello Alex!

    First and foremost, thanks for the tutorials because they are quite awesome!

    As for my problem, the for loop in my void shuffleDeck() function just doesn’t seem to work properly. It only runs once so it swaps the first card with a random card then the rest of the deck is left untouched. If I go through the loop in the debugger it works as it should(I went throught the whole for cycle) but I couldn’t figure out why it fails doing so after I compile it.

    Thanks,

    Greg

    P.S.: I disincluded the enum classes, the struct and the printCard() function because the code was twice as long with them.

    • Alex

      First off, you are picking a random number between 1 and 52, but your deck array’s indices go from 0 to 51. That’s a bug, but not the reason your program isn’t working as expected.
      Second, you’re instantiating a mersenne random number generator to initialize your built-in random number generator with. That’s weird. Either use mersenne or rand(), but not both.
      Third, you should only instantiate your random number generator (and/or use srand()) once, not every time the function is called. I suspect this is why your randomness is failing.

      When I deleted the first two lines of your randomGenerator() and added the following line to the top of main():

      (and fixed the array indices issue), everything worked fine.

  • phyer

    so far, the best tutorial I have ever seen.
    I love these quiz.
    keep up the good works.
    thank you so much.

  • Baubas

    Hi Alex,

    quiz 2:
    Why can’t I use
    std::getline(std::cin, arrayNames[iii]);
    instead of
    std::cin >> arrayNames[iii];

    If I use the first line I got this:
    How many names: 3
    Enter name nr.1: Enter name nr. 2: aaa
    Enter name nr.3: bbb

    I don’t have the possibility to enter the first name.

  • 6h solution has an error: there’s no default return value.
    Generally compilers will complain and will not let such code compile. However if they do, this is still a mistake since if somehow card.rank is set to MAX_RANKS or an unhandled case, and function might return garbage, or the program may be as well terminated.
    It might be a good idea to add return 0 or -1 to either default case, or end of a function.

  • Nortski

    Excellent tutorials!

    I just need to get my head around how to structure a program, calling functions within functions blows my mind!

    I have a question regarding quiz number 7. Why do we pass a pointer into getCardValue()?

    • Alex

      > Why do we pass a pointer into getCardValue()?

      We don’t. We’re dereference cardPtr, which gives us a Card object. This Card object is passed into getCardValue().

  • Marc

    Really amazing quiz.  Ty Alex.

    Silly question but why is the array declared to 52.  Shouldn’t it be to 51 since 0 counts too?

  • Ran

    Problem?

    Why the quiz 2 is the same with Chapter 6.9a’s quiz?

    • Alex

      I’m not sure how that happened. I’ve updated the question to something slightly more complex, but that should be doable if you successfully completed the quiz question for chapter 6.9a.

  • Rob G.

    For #2: Alex am I correct that there is no way to put

    into
    any place other than main() because of scoping issues? I am pushing hard on compartmentalization.

    Also your solution uses [] for array indexing/sorting operations, etc. I coded mine using pointers - is one preferred more than the other?

    • Alex

      Yes, main() is the best place for my_array in this case. You can maintain compartmentalization via use of functions, which you have.
      Array subscripting is almost always used for directly indexing an array, because it’s easier to read, and you’re less likely to make a mistake. Pointer arithmetic is usually only used when you have a pointer that you’re stepping through an array.

  • Rob G.

    Alex you have a great site. Have learned so much from it. I noticed in quiz#3 that I can only pass "magical" numbers as an argument to the functions parameters so long as the parameters are not referenced (minus the ampersand). With symbolic language there is no problem.

    error: ..srcmain.cpp:20:17: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’

    • Alex

      Yes, because a and b are non-const reference variables, which require the arguments to be an lvalue (have a memory address). Literals (such as 5) don’t have an address. What does it mean to swap(3, 1)? 3 has the value 3, and 1 has the value 1. You can’t make 3 have the value 1 or vice versa.

      If you remove the ampersands, then a becomes a copy of the first argument, and b becomes a copy of the second argument. The function then swaps these copies. Finally, when the function ends, the copies are destroyed. The original arguments are left alone. So while it compiles, it’s pretty useless, because swap (a, b) would swap a copy of a with a copy of b, and the original a and b would still have their original values.

  • Thomas

    Great tutorial, Alex. I’m at my final semester in computer engineering, had two courses of programming, basic & object-oriented, both in c++.
    This site’s explanations are of much higher quality (imo) and easily replaced my lecturer and his lectures.

    Good job!

  • Ran

    Hi~Alex:

    How to change my head portrait in your comment area?

  • Ran

    This is a test for my new portrait!

  • Arda

    Hey Alex, I found a mistake in your article. In quiz 1 you said, "Player should start with 20 arrows." but in the program you wrote, you gave the player 10 arrows.

    Have a nice day! 🙂

  • Rob G.

    Hi Alex I think I over thought question 2. Can you please clarify how you kept the names and grades paired? I’ve missed a simpler step and would like to know what that was.I solved the problem (below) using an array of structs. I would sort the structs based on the grades, and since the names were in the same struct, I didn’t have to worry about keeping them paired. But of course dealing with an array of structs was very educational so it was worth the effort.

    • Alex

      It looks like you basically did the same thing I did, just with more modularization. I also used an array of structs, sorted by grade. Although we’re sorting by grade, we’re swapping at the struct level, so we’re swapping the name and the grade together.

  • Sandro

    About the quiz #2.

    In your solution you pass the array to the sortNames function. I imagine that it decays to a pointer. So, why didn’t you need to use the member selection operator (->)? It worked like a normal array to me.

    Another question. I don’t know why, but my program works without the utility operator. I tested the solution too. Can someone tell me why?

    • Sandro

      I also tried on an online compiler. It worked as well.

    • Alex

      I don’t need to use operator-> because the subscript operator[] does a dereference. That is, students[currentIndex] returns a value (of type Student), not a pointer to a value. So we use . instead of ->.

      By “utility operator”, I presume you meant utility header. It’s possible that your iostream or string libraries are including utility themselves, so when you include them, utility comes along for the ride. But you should not rely on this.

  • Aymen

    Hi Alex, really frustrated with a problem I’v been having and done multiple searches online to see if any one else has been having this problem and it appears there problem isnt directly similar to that of mine.

    For the code

    I have been getting the error:

    error: aggregate ‘std::array<Card,52u> deck’ has incomplete type and cannot be defined

    I think that this may be an error with my compiler as I have done basically the same to your solution and just to ensure that its my compilers fault, I have started a new file and copied each of your solutions from the Task6 and beyond up to 6d and got the same problem.

    Any help would be strongly appreciated.
    Cheers

    • Alex

      I’m not sure if this is your problem, but you can get this problem when the compiler can see that there is a struct or class named Card (though a class forward declaration) but can’t find the implementation.

      Make sure the definition of struct Card is above your main function, where you declare the std::array of Cards.

      • Aymen

        I did Alex, but me being an idiot as usual forgot:

        So yeah, It took me a day to figure out where I’d gone wrong, I put it in at the start and then changed it to vector for some reason or another. Anyways thanks for the help and hopefully no one else will make this mistake reading!

  • Rob G.

    Hi Alex,

    In general, I am using fewer raw pointers and more dereferencing subscripts for readability, etc. For exercise 4,
    is there some significance to why you chose to use pointers in this case? Can u plz clarify when to use pointers versus dereferencing subscripts?

    of course the pointer value and the array value are the same.

    • Alex

      I used a pointer because the quiz question said to use one. 🙂

      Generally speaking, subscripting is favored because it’s easier to use and does an implicit dereference. Pointer arithmetic may lend itself to a more elegant solution in rare cases (e.g. copying a C-style string), but it hardly matters.

  • Sandro

    Hello. For the #7 quiz, I wrote the program below. It works, but if you play it several times (the game allows you to keep playing), the variables starts to get weird numbers, like 20030006113. Can someone explain me why?

  • Jazz

    Hi Alex,

    I want to share a beauty with you, with the next swap function in #3 quiz:

    Many thanks to you, Alex!

    • Alex

      This is a neat little integer trick that sometimes gets asked in programming interviews.

      Please don’t ever do this in real code, as it’s not obvious what the code is doing. 🙂

      • Jazz

        I’m agree with you, it’s realy looks like "magic literals". But, what about algorithms, that are not obvious too?
        This function returns Greatest Common Divisor, and it doesn’t look simple.

        Or i’m talking about different things?

        • Alex

          Good question and food for thought. I think the difference is this:

          * There’s a good alternative for the swap() function that’s not only more intuitive, but also works for non-integer types (use a temp variable, or std::swap). The algorithm presented above is “clever” (which makes it an interesting interview question), but clever isn’t a good qualification for an algorithm.

          * There isn’t really a good alternative for the GCD algorithm that’s going to be more intuitive, and GCD is only meaningful in the context of integers anyway. This is a standard way of calculating GCD. I think in this case, a good comment will go a long way.

  • Satwant

    Quiz 2, in solution line no. 22.

            // Look for largest element remaining in the array (starting at startIndex+1).  // WRONG
            
                   // Look for largest element in the remaining array( starting at start index+1).  //RIGHT

  • Soul

    EDIT: Never mind, just went back to the chapter on for each loops and discovered they don’t work on dynamically allocated arrays.

    Hi, I’m having some trouble here:

    This give me an error at the first for each loop, and says something along the lines of 'no matching function for call to 'begin(students*&)'.

    I have yet to implement anything else but was giving my current code a test run until I came to this little problem. I have no idea why this is giving me issues.

    Please help, thanks.

  • Soul

    Hi,

    Ummm, I just popped in the code in answer #7 and my compiler can’t make it work. I get the error "warning: enumeration value ‘MAX_RANKS’ not handled in switch [-Wswitch]|". There’s another like it underneath it that mentions MAX_SUITS.

    When I commented them out, I got RAND_MAX was not declared in this scope for line 88.

  • Rob G.

    Hi Alex I am struggling with 6d: I didn’t end up using static casts or enumerators. Am I missing the point here?
    The code is similar though. Do I need to rewrite my solution?
    your solution:(comparing yours/mine)

    …yours
        {
            deck[card].suit = static_cast<CardSuit>(suit);
            deck[card].rank = static_cast<CardRank>(rank);
            ++card;
        }

    [/code]

    My solution:

    • Alex

      Using enumerators is clearer than using integers since it’s more self-documenting. Which integer suit represents hearts? I have no idea.

      Having an index member in your card is a little odd. Typically you want to rely on your container (in this case, the array) to provide the ordering, not make the cards themselves responsible for knowing how they are ordered.

  • Rob G.

    Hi Alex, I accept your teaching points on enumerators, self-documentation, etc. But I am still trying to sell myself on it.
    Is it true that enumerations only go "one -way" meaning:

    enum foo
    {   submarine 3,  //explicit values
        carrier 4
    }
    They resolve to an integer: x = submarine  (3).

    However, you can’t go backwards from 3 to submarine. How is this helpful?

    "Which integer suit represents hearts? I have no idea." Even with enumerator, you will still have to look it up right?

    Or can it?

    You’ve got a great site, learning so much from it. Enumerators are my weak "suit" no pun intended. I am just seeking understanding.

    • Alex

      Enumerators aren’t strictly one way. Normal enumerators will silently convert to an integer. However, you can explicitly convert an integer to an enumerator by using a static_cast.

      Generally you shouldn’t ever need to convert from an integer back to an enum.

      Perhaps the best way to think of enumerators is as descriptive names for a set of integers. Like you said, you have no idea which integer suit represents hearts. You could arbitrarily pick a value (0, 1, 2, or 3) but it’s not very self-documenting. However, if you use an enumerator, it’s clear which one is hearts: SUIT_HEARTS is hearts. This relieves you from having to remember the integer/concept mapping, and makes your code clearer.

  • Rob G.

    I hate to ask this, I don’t want to monopolize the forum. Can you make a small example of the latter part of your response? I’m very close to understanding. Thx

  • Rob G.

    Alex, I think I get it! In any event I see that a lot of enumerator benefits are for the programmer’s side. The static cast allows an integer to be an enumerator…Briefly what are the most appropriate situations in which the conversion of integers to enumerator would be applied?

    • Alex

      Yes, enumerators are for the programmers benefit, because they are a more descriptive way to label a set of discrete items than picking an integer.

      I think the only case I’ve ever done an integer to enum conversion was for randomly picking (or generating) items from a set of enumerators. Generate a random integer between 0 and MAX_ITEMS-1 (where MAX_ITEMS is the last enumerator) and then static_cast the result back to an enum.

  • Rob G.

    Hi Alex in my shuffle deck function I am not getting 4 of every card type, randomized, in my output.

    My shuffle fx:

    I call the function to generate the random number inside the shuffle fx:
    srand() is at top of main.

  • Rob G.

    oops, forgot output:

    [output]

    Shuffling deck…
    Cards to be swapped:
    0    48
    1    29
    2    46
    3    9
    4    15
    5    39
    6    47
    7    36
    8    26
    etc…
    [/output]

    • Alex

      I’m probably missing something obvious, but… what do you think is wrong here?

      It looks like your cards should be getting shuffled properly.

  • Rob G.

    Let me post an expanded pool…52 swaps. There are duplicates in this array. The intent was to step though the array, as you suggested, and swap with a randomly generated card.
    Simple enough except my implementation is faulty….ideally you don’t want a duplicate correct? The unshuffled deck is on the left and the shuffled on the right. I am sorry the output takes up so much room.

    0    7
    1    47
    2    16
    3    18
    4    6
    5    36
    6    2
    7    15
    8    33
    9    1
    10    40
    11    47
    12    16
    13    5
    14    13
    15    14
    16    46
    17    14
    18    8
    19    43
    20    40
    21    35
    22    26
    23    41
    24    22
    25    10
    26    26
    27    6
    28    52
    29    26
    30    9
    31    29
    32    6
    33    52
    34    45
    35    19
    36    46
    37    46
    38    7
    39    32
    40    3
    41    37
    42    6
    43    23
    44    31
    45    1
    46    39
    47    4
    48    15
    49    16
    50    12
    51    19

    • Alex

      No, it’s okay to have duplicates in this case. We’re not pre-determining a new ordering of cards, we’re just picking a random card to swap with and doing the swap immediately. Because the loop ensures each card gets swapped at least once with a randomly chosen card, this results in a pretty good shuffle.

      Consider what happens if two cards pick the same card to swap:
      2 1
      3 1

      First, card 2 will be swapped with card 1. Then card 3 will be swapped with card 1 (which was the card in 2). So the new order of cards 1 2 3 is 3 1 2.

  • Rob G.

    Hi Alex, am getting duplicates. As in the values above. Random fx and swap fx below. Is it as simple as the fact that the random number generator can produce copies in this short range? First do you agree there are duplicates?
    Fx returning random val 1->52.

    Fx shuffling the deck using random value call.

    Thx Alex

  • Baubas

    Quiz 4:

    I did it with for:

    Why can’t I use "ptr < word + sizeof(word)" but this version "ptr < word + 13" works fine?

  • tejas

    I had great fun writing my very own BlackJack game! Got interested in writing games and am now working with a buddy to create a military battle game like the "World War 2 in Western Europe" (1995).

  • Shiva

    Alex,

    Awesome quiz to wrap up the chapter! Just loved it, especially #6-7 Blackjack game. Being an advocate of bottom-up designing, I enjoyed the way you made us build it from scratch, writing the individual modules first and then finally putting them all together. And all the stuff I’ve learned from here so far was put to test. I think I did it pretty well. 😀 And great summary, too.

    BTW I’ve got some suggestions:
    * In quiz #1 solution, the enumerator’s name is given as ITEM_HEAL_POTION (you asked us to enumerate ‘Health potions’)
    * In multiple solutions, you used the [] syntax while passing arrays to functions, but you recommended using the pointer (*) syntax before. I think this was deliberate in the context of quiz #5 c), but you should be consistent in the rest of the solutions.
    * In your Blackjack game, you pass the std::array deck to playBlackjack() by value, not by reference. Typo?

    Lastly, I found an alternative solution to quiz #6 h) : pass the player’s current score as a second parameter to getCardValue(), and let it determine what value to return for an Ace. This is what I did, and I think it’s neat:

    I’m tempted to post the whole solution, but it is some 350 lines, so I’m not cluttering this comment section with all that code. However you can view it on my GitHub if you have some time to spare. I’d greatly appreciate it. 🙂

    Thanks once again, expecting more such challenges!

    • Alex

      Thanks for the feedback!
      1) Changed enum to ITEM_HEALTH_POTION for consistency.
      2) Good call. Updated the syntax to use the pointer syntax over the array syntax.
      3) Yup, the pass by value instead of reference was unintentional. Fixed.
      4) I think this works for one ace, but what if the user has more than one ace?

      • Shiva

        Umm.., I believe it still works for more than one Ace. The current score is updated every time getCardValue() is called, so the function receives the latest score to calculate the suitable value for an Ace. Even if the first two cards dealt to the player are Aces, it can handle it well:

        Suppose the player Hits, and he gets yet another Ace:

        This way we need not count the Aces a player has, since we’ve checked it _before_ we incremented their score. I mean, that’s how we do it in real life: we draw a card, and consider our current score before choosing the suitable value, not after. Is there anything missing?

        And I just noticed some more typos:
        * In the solution to quiz #2, you still have the [] syntax while passing the array to the sortNames() function. The comment just above its definition is also broken: "Since names (should be ‘students’) is a pointer…"
        * In your Blackjack game, you passed the deck to printDeck() by value too.

        Thumbs up for the quick corrections. 🙂

        • Alex

          You are correct indeed! I’ve added it as an alternative solution to the final quiz question (with credit to you, of course).

          • Shiva

            That’s so nice of you. Appreciate it. 🙂

            So I won the extra credit, didn’t I? B-)

          • Tyler

            The only problem with this is that if the player or dealer drew an ace before it would’ve busted him/her, there is no way for this ace to return to the value of 1 later.

            Say:
            Player draws an ace
            Player draws a two
            Player hits and draws a ten

            Then the player is stuck at a bust regardless of having the ace. While it’s much simpler it doesn’t cover all the bases.

  • Peter Pan

    I have a very complicated solution for 6h. Like for example, the player’s score is 3. Then he hits and gets an ace. So his score can be 4 or 14. Then he gets a nine, so his score is now 13.

  • Satwant

    Please remove "words of encouragement ". Its highly distracting.
               In normal course of this tutorial, finding something irrelevant ,it completely gets you out of track.

    • Alex

      Some readers may find the difficulty of chapter 6 discouraging. This section exists to let them know that good things are ahead, that their struggles are worthwhile.

  • Amin Ashofteh Yazdi

    In the name of God

    Hi
    Dear Teacher,
    i am in problem with design nested loop, and need to train my brain, in first step i use flowchart but i want to know that is a simple or logic way to reach to this power .
    thank for any of your guides.

    Hope to God

  • J3ANP3T3R

    Words of encouragement

    Congratulations…

    YEAAAHHH !!!!! AAWWEESSOOOMMEEE !

  • J3ANP3T3R

    Oh i hit a dead end. need to go back and review the previous articles.

    i did not know that "int items[MAX_ITEMS]{ 2, 5, 10 };" works given that the array item was not dynamic. it is highlighted in red line by the IDE but the compiler did not give any errors.

    also thought that when passing fixed array on functions it will decay into a pointer and could not be used in the function as a regular array. wasn’t aware that i can still use it to loop through the elements in the actual array.

    this quiz is very enlightening. i basically failed this chapter >_<

    • Alex

      This chapter is hard. It introduces a lot of complicated topics, and those complicated topics have some weird behaviors.

      The good news is that things generally get easier ahead.

  • Nyap

    damn this test is long
    also, I struggled this chapter, and I won’t be suprised if I fail ;-;

    • Nyap

      whats wrong with this (I know I should probably use std::vector but I rushed the lesson on it because I just want to get this chapter done and over with :cry:)

      output:

      How many students do you wish to enter?: 2
      Shrek
      50
      Hitler
      75

      50 got a grade of 0
      75 got a grade of 0

  • Nyap

    Question 1:
    http://pastebin.com/btw9BJJ0

    Question 2:
    http://pastebin.com/aCcGsY8D

    Question 3:
    http://pastebin.com/ySuTzam9

    Question 4:
    http://pastebin.com/XzeDP4dJ

    Question 5;
    Did it in my head, got most but one right

    Question 6 and 7:
    Know nothing about card games and I can’t be bothered to learn them just for this test xD

    overall I think I did ok, just need to review std::array and std::vector

  • Darren

    Not one for letting an argument die but I’ve refactored your code for the player’s loop to remove the break statement. The original code reads:

    The refactored code looks like this:

    Not only does this remove the break statement it also mirrors the loop for the dealer’s turn, without the call to ‘getPlayerChoice()’ of course. To me this reads better.

    • Alex

      Of course, now you’ve duplicated the output line to tell the player what their score is. To me, redundancy is a bigger sin than a break.

      • Darren

        That’s not a redundant line. The player needs to see their score in order to decide whether or not to stick or to hit on the first entry to loop. But notice that if they already have 21 i.e. blackjack (ace and a picture card) there’s no need to enter the loop, they’ve already won (this requires an if conditional with a return value of true somewhere). If what you meant was repeated code, then I’m willing to trade a single line of that for removal of a break statement in the middle of a while loop.

        • Darren

          Besides we could always change the initial output message to something other than that repeated in the while loop and then the lines wouldn’t look as repeated as they do!! 🙂

  • Vlad

    Well, this was quite the heavy quiz. To me, pointers are still fuzzy (not by their meaning, but rather all their combinations), as well as interweaving enums and structs and arrays (I didn’t quite figure that out by myself).

    But, I made it. Probably childish code, though due to some minor misunderstandings, I made the blackjack a bit different. I won’t post the code, it’s long enough (I will if you want to), but here’s what it outputs (one example):

    There still is a small problem with displaying the cards after hitting ‘s’ (the first cards are not displayed, it’s some pointer magic), it’s something very small but right now, I deserve a break (excuse for a beer).

    Because yesterday I made a Bessel polynomial generator with user input (I had to find an external, small library to support more than long long, it needs (2*N)! -- ttmath) and I feel confident enough that I can create a root finding algorithm (Durand-Kerner) and then it’s off to my initial goal and the starter of this C++ quest (not saying yet, there’s time).

    So, here’s a virtual cheers: to you, Alex!

    PS: I wanted to ask you, are symlinks similar to pointers?

    • Alex

      I’d say symlinks are more like references than pointers.

      • Vlad

        I can almost hear a voice saying: "That’s English language to you! The symlink is said to point to another location via a reference." 🙂

        Now see I forgot to modify the output. I set codeblocks to use the basic xterm for output, and it doesn’t allow copying, neither by RClick or Ctrl+Insert (or Ctrl+Shift+Insert, I tried). So, after 3 runs, seeing that the program doesn’t output what I want, I thought it simpler to just visually copy-paste a line and modify it, rather than modify the code, compile, run, and then visually copy-paste. That’s why the first "dealer’s cards" says AS 11p, but the rest 4p. Ah well…

  • DianYi Liu

    Hi,Alex,thank you very much!I read this great tutorial from beginning!
    In your function of playBlackjack(),I think there is a little problem. If after shuffleDeck, the 2nd’s and the 3rd’s cards’ ranks both happen to be Ace, then the program will say the player wins. But player’s score has already gone over 21. Player should lose.
    So, just after dealing the player the first 2 cards, some codes should be added to decide whether player’s score has gone over 21 or not.

    • Alex

      True. I’ve reordered the statements in the player’s while(1) loop to first check to see if the player is busted before asking them if they want to hit or stand.

  • Hans Dampf

    Two minor questions about your solution for the Blackjack program:

    1)

    Since there are only two options, wouldn’t it be better to return a bool value (if user enters ‘s’ return true)? I don’t know what’s best practice. Does it even matter? Both char and bool use 1 byte. Later in playBlackjack, we would then just check

    and 2)
    This is about the "no magic numbers" rule. Instead of declaring the array with

    why not use our MAX_SUITS and MAX_RANKS?

    Likewise

    • Alex

      1) You could return a bool in this case if you wanted. I chose to return a char to leave room for future choices (e.g. double down).
      2) You definitely could do this as well. In fact, you could probably use a constexpr constant to give MAX_SUITS * MAX_RANKS a better name (e.g. NUM_CARDS).

  • David

    I tried ex 2.This is the code:

    As i writed in the comment if i change from this "<" to this ">" my program crashes.I must mention that at first i ran the program without deleting the array.Eventually I noticed and i deleted the array.

    Can you tell me what is the problem?
    Thank you for your tutoriols.You are doing a great job

  • Seamus

    Hello,

    First of all, fantastic tutorials.  Thank you.

    I’m trying to write the program for problem #7, but for some reason the compiler is throwing up a warning on the line:
    getCardValue(*cardPtr++)
    saying that expression (cardPtr) must be a pointer to a complete object type.  This only occurs when I include the ++ operator.  It looks exactly like the code suggested.  Please help.

    • Alex

      I’m not sure. You can break this up into two equivalent lines:

      See if your compiler is okay with that.

      • Seamus

        Still not working for the same problem.  Here’s some of the surrounding code to give it more context.  The error is on the pointer being incremented:

        bool playBlackJack(const std::array<Card, numCards> deck)
        {
            const Card *cardPtr = &deck[0];
            int pScore{ 0 };
            int dScore{ 0 };
            dScore += getCardValue(*cardPtr);
            cardPtr++;
        }

        • Alex

          I think something else is going on here. Best guess is that whatever file this is only sees Card as a forward declaration instead of a complete class. I’d investigate why this function can’t see the complete definition for Card (maybe you forgot to include Card.h?)

  • Alexander

    Can’t really decide whether to be proud of my elegant solution to 6e), or ashamed that the reason I tried to find a substitute for the obvious switch was literally just that I was too lazy to type that much! I guess programming is about optimization, so… 😀

    • Alex

      Cool solution, though rankChars and suitChars will have to get initialized every time the function is called. You should make them static so they only initialize once (since they don’t change).

  • HI Alex,
    Having one doubt.
    While trying to print the deck. I used value "10" instead of "T" like "case RANK_10:std::cout << ’10’; break;" here am a using value10instead of ‘T’. But am getting some garbage value instead of 10. why it’shappening

  • Kārlis

    Why is it neccessary to write:

    int getCardValue(const Card &card)

    in task 6h instead of just:

    int getCardValue(Card card)

    ?

    • Alex

      It’s not necessary, it just avoids an making an unnecessary copy. In the latter case, the value of the argument will be copied into parameter card. In the former, reference variable card will be used as an alias for the argument, so no copy is made.

  • Kārlis

    So I wrote a code for Blackjack game. I wanted for program to show not only score but drawed card as well. The code got longer and didn`t look good. To make code more readable I invented new enum:

    Now I want to make a single function drawCard(PlayerType playertype) which would contain printCard(..) and getCardValue(..) so that my main() would look like this

    can I declare both dealer and player scores as global variable so that drawCard() would change the value if them accourding of input(player/dealer)? In tutorial you suggested to stay away from them. Is there a way to reset the value of glabal variable if I wanted to implement play again function?

    • Alex

      I still suggest you stay away from them. Instead, I suggest you pass playerTotal and dealerTotal as reference parameters to your drawCard() function. This will allow drawCard() to modify those values directly. See lesson 7.3 if you need more help with reference parameters.

  • Kees

    I made a typo in the code of question 4. (std::cout << str; instead of std::cout << *str;)
    The result was:

    Hello World!ello World!llo World!lo World!o World! World!World!orld!rld!ld!d!!

    Why does i print this?

    • Alex

      str is a pointer to a char. std::cout assumes that pointers to chars are meant to be printed as strings, and will print everything from the first character being pointed to until it hits a null terminator. So first, str points to the H in Hello world!, which prints the entire string “Hello world!”. Then you increment str, so it now points the e, which prints “ello world”. And so on, until str points to the string’s null terminator and the loop condition exits.

  • asker

    Help me the question commented in the code bellow:

    Thanks in advance.

    Edit: ah, I’ve seen that the variable total is not set to 0. 😀

    Edit2: After I edited this post, the [code] tag would not work??? Sorry if it’s my mistake.

  • Matt

    I loved your Blackjack challenge. I finally wrote a program that seems to serve a purpose… and I only cheated on the random number formula.

    Also, I noticed a mistake in your blackjack solution. When the dealer is dealt his first card, the comment says the the player is given the card.

  • Turya

    Hi,

    Just wanted to crosscheck the extra credit problem. Any comment is welcome

  • Andy

    Hi There, love this site.
    I have completed question 2 but now instead of my own sort i am trying to use std::sort from <algorithm> but getting a compiler error.

    I am using :

    and i get an compiler code:
    error: request for member ‘begin’ in ‘students’, which is of pointer type ‘Student*’ (maybe you meant to use ‘->’ ?)|

    error: request for member ‘end’ in ‘students’, which is of pointer type ‘Student*’ (maybe you meant to use ‘->’ ?)|
    Can you provide some insight as to what i am doing wrong?
    thanks

    • Alex

      Yup, but explaining it in a way that makes sense at this point in the tutorials is a little difficult.

      std::sort is implemented using iterators (a topic that I haven’t really written a tutorial about yet, but plan to soon). Basically, iterators provide an abstract way to step through each element in a container (such as an array). begin() is typically used to get an iterator to the first element, and end() is typically a special symbol representing the end of the list.

      The problem here is that students is a C-style array. C-style arrays don’t know anything about iterators.

      So, the simplest solution here would be to change students to a std::array or std::vector, as both of those classes contain built-in support for iterators.

  • Gapo

    Is it bad if I almost always need to look into solutions in order to finish my quiz ?

    • Alex

      It’s not ideal. But comparing the reference solutions with your provides another avenue for learning. As long as you’re reading the solutions and understanding them (and where you went wrong), you’re probably okay. You might want to find some additional quizzes on other sites to reinforce your learning.

      • Mateo

        Thank you for replying Alex .
        I will just keep trying until I make sure I understood the whole chapter. I do sometimes feel to stupid for this but that’s not gonna stop me. This is my first programming language ever so it was probably a bad idea to choose such a hard language as my first one . Anyway I love c++ and I won’t rest till I master it .

        • Alex

          C++ certainly isn’t the easiest language to learn -- other toy languages like Pascal are a bit easier because they are simpler. But the advantage of C++ is that you’re learning something that’s actually useful. Nobody writes applications in Pascal. Stick with it!

  • Nelson

    Hi Alex,

    Thx for all this information, it’s been a very nice read!

    Now, when writting my code for the card game, i got stuck in 6g and when I solved this issue, I never really understood what happened.

    I created several files for the project.  I included my enums in the header "Enums.h", my functions in a separate file named "Functions.cpp" and added a header for forward declarations named "Forwards.h"

    It all worked well until I wrote shuffleDeck().  At this point, i always got the error

    error LNK2019: unresolved external symbol "void __cdecl shuffleDeck(class std::array<struct Card,52> const &)"

    I read my function over and over, it was fine.  So, I moved the function definition to the same .cpp where my main() was, and voila, it all worked.

    So, my question is: Why did this particular forward prototype gave an error or why did it work when i moved the function to the same file where my main() was?

    Hope I was clear explaining my doubt.  
    Thanks in advance,

    • Alex

      I’m… not sure. It sounds like maybe the function wasn’t getting compiled when it lived in the header file. Either the header wasn’t being properly included or the header guards were preventing compilation for some reason.

      As a side note, organizing your code by “function” (enums, functions, forwards, etc…) generally isn’t the best way to organize. You’re better off organizing by feature area (Card, Deck, game, etc…).

  • Mike

    Why isn’t this compiling please help Alex and others.
    #include "stdafx.h"
    #include <iostream>
    #include <array>
    #include <ctime>
    #include <random>
    using namespace std;

    enum  Cardrank
    {
        _1,
        _2,
        _3,
        _4,
        _5,
        _6,
        _7,
        _8,
        _9,
        _10,
        Jack,
        Queen,
        King,
        Ace,

    };

    enum  Suit
    {
        Club,
        Diamond,
        Heart,
        Spade,

    };

    struct everycard
    {
        Suit suits;
        Cardrank cards;
    };
    void printCard(const everycard &card)
    {
        switch (card.cards)
        {
        case _1:                          cout << "1"; break;
        case _2:                          cout << "2"; break;
        case _3:                          cout << "3"; break;
        case _4:                          cout << "4"; break;
        case _5:                          cout << "5"; break;
        case _6:                          cout << "6"; break;
        case _7:                          cout << "7"; break;
        case _8:                          cout << "8"; break;
        case _9:                          cout << "9"; break;
        case _10:                          cout << "10"; break;
        case Jack:                          cout << "J"; break;
        case Queen:                          cout << "Q"; break;
        case King:                          cout << "K"; break;
        case Ace:                          cout << "A"; break;
        }

        switch (card.suits)
        {
        case Club: cout << "C"; break;
        case Diamond: cout << "D"; break;
        case Heart: cout << "H"; break;
        case Spade: cout << "S"; break;

        }
    }

    void printdeck(array<everycard, 52> &deck)
    {
        for (auto &card : deck)
        {

            printCard(card);
            cout << " ";
        }
        cout << ‘\n’;
    }
    void swapCard(everycard &a, everycard &b)
    {
        everycard dor = a;
        a = b;
        b = dor;
    }

    int getRandomNumber(int min, int max)
    {
        static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0);  // static used for efficiency, so we only calculate this value once
                                                                                     // evenly distribute the random number across our range
        return static_cast<int>(rand() * fraction * (max - min + 1) + min);
    }

    void shuffleDeck(std::array<everycard, 52> &deck)
    {
        // Step through each card in the deck
        for (int index = 0; index < 51; ++index)
        {
            // Pick a random card, any card
            int swapIndex = getRandomNumber(0, 51);
            // Swap it with the current card
            swapCard(deck[index], deck[swapIndex]);
        }
    }
    int getCardValue(everycard &card)
    {
        switch (card.cards)
        {
        case _1:                          return 1;
        case _2:                       return    2;
        case _3:                         return  3;
        case _4:                     return      4;
        case _5:                           return 5;
        case _6:                          return 6;
        case _7:                           return 7;
        case _8:                            return 8;
        case _9:                           return 9;
        case _10:                         return  10;
        case Jack:                        return  10;
        case Queen:                       return  10;
        case King:                        return  10;
        case Ace:                         return  11;

        }
        return 0;
    }

    int main()
    {

        array <everycard, 52> deck;

        int card = 0;
        for (int suit = 0; suit < 13; ++suit)
            for (int rank = 0; rank < 5; ++rank)
            {
                deck[card].suits = static_cast<Suit>(suit);
                deck[card].cards = static_cast<Cardrank>(rank);
                ++card;
            }

        printdeck(deck);
        shuffleDeck(deck);
        printdeck(deck);
        return 0;
    }

    • Alex

      It compiles fine for me (but crashes when running). What compile error are you getting?

      • Mike

        Sometimes it randomly throws of an error that can’t open the file which contains solution, but it crashes everytime too.
        Why does it crash ?

        • Alex

          If you run your program in a debugger it should tell you.

          The problem is this line:

          This is causing an out of array bounds issue (rank should go from 0 to 3, not 0 to 4).

  • Jared

    Hey, Sensei Alex!
    … I got stuck on Quiz #2
    In the following excerpt: