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 first 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 grade pairs, sort the list by grade (highest first). Then print all the names and grades in sorted order.

For the following input:

Joe
82
Terry
73
Ralph
4
Alex
94
Mark
88

The output should look like this:

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

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?

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.
Hint: Don’t forget that std::array’s operator[] expects an index of type size_type, and that size_type must be prefixed by the full name of the array type to be accessed.

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 (and the player has not gone bust), the result is a tie and neither wins. Describe how you’d modify the above program to account for this.

Show Solution

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

513 comments to 6.x — Chapter 6 comprehensive quiz

  • Peter Baum

    There is nothing wrong with the solution given, but I thought for item 6g I would try to avoid shuffling by moving the structs around, which in general would be a costly thing to do.  Instead I created an index array holding elements 0 through 51, and just shuffled the index of ints.

    There were some things that came up though that it would be nice to get some comments or suggestions on from the experts here.
    1. Did I get my arguments and parameters right?  I still feel weak in that area.

    2. Should I move the globals I used for the Mersenne twister somewhere else?  If so where?

    3. Having to static cast the enums seems like a language flaw.  Are there any other more elegant alternatives?

    4. In printShuffled() I passed both the deck and the shuffle array.  Is there a better way to do this?

    Any and all comments are welcome.  I know some people won’t like my cardDeck initialization, but showing that there is another way might be interesting to some people.

    It would be nice for more than one good solution be presented.  I always learn things by looking at code written by talented programmers. (I am NOT suggesting to use my code.  I have prior programming experience, but I am just learning CPP.  I’m sure there are plenty of experienced CPP coders who would be willing to help.)  In addition, by showing multiple solutions, one gets to see that there are many good programming choices for any project, many tradeoffs are involved, and it is good to start thinking about these algorithm choices since it is such an important part of programming.

    • nascardriver

      Hi Peter!

      You're right about Alex' @shuffleDeck (more specifically @swapCard) being slow and your solution works around that. But you're not actually shuffling the deck anymore and you need two arrays to keep track of cards which is a bad solution in my opinion. A nicer solution would be dynamically allocating the cards and only storing pointers in the array. That way we can swiftly shuffle the deck but stay with one array.
      The easiest solution is replacing @swapCard with @std::swap. @std::swap performs the swap using @std::move (Chapter 15).

      1. @printCard should take a const reference, but reference parameters haven't been covered yet so everything is fine.

      2. Definitely. Move them inside @shuffleDeck, because that's the only place you're using them. Declare them static so they don't get re-created with every call to @shuffleDeck.

      3. Use regular enums (declared in a namespace/struct/class to avoid duplicate names).
      I don't like giving this advice, but if you really don't like casts this is the way to go.

      Suggestions:
      * Use documentation comments for your function descriptions.

      * Sort your includes alphabetically (But don't mix local with global).
      * 52 is a magic number, declare a constant for it.
      * Line 54: You're not emptying any buffer, you're appending a line feed.
      * Line 60: @std::uniform_int_distribution generates numbers from a to b, not between a and b
      * Line 82: If you're not using a constant for 52, use @std::array::size
      * Line 84, 88: Magic numbers, you have enumerators for 13 and 4
      * Don't use @system unless you have to. "pause" is a Windows only command. Use @std::cin.get or @std::cin.ignore. If you so use @system, use @std::system. It's the same function but officially it should be declared in the @std namespace, I'm yet to encounter a platform that strictly follows this rule.

      • Peter Baum

        Hi nascardriver,
        Excellent suggestions.  Thank you for taking the time.  The only thing I wasn't sure about was line 54 and emptying the buffer.  I think I read that someplace and I assumed it was true.  I'm not sure how to test it.
        Thank you again.

  • Peter Baum

    Comments on solution for 6C.
    1. The & is not needed for parameter card
    2. Rather than a switch statement, I suggest

    The +1 for the index could be simplified but I made the rank values the same as the card values at this point because I don't know how it is going to be used. Alternatively I could have created another enum for this array size purpose. I made the Joker rank 0 and Ace rank 1.

    • nascardriver

      Hi Peter!

      1. Reference parameters haven't been covered yet so there's no reason for you to know this. Anything with a non-standard size (1, 2, 4, 8, 12, 16 bytes) should not be passed by value, because it's slow. Passing a parameter by reference uses 4 or 8 bytes no matter how large the object is.

      2. Now you're relying on the enum to be numbered consecutively and you made it a whole bunch more difficult to figure out which character corresponds to which enumerator.
      Scenario: You give your code to a friend, they add a card to the enum, everything is broken. If you used a switch they'd get a compiler warning, if they have enabled it, or they'll get an empty output, which is still easier to debug than wrong output.

      Use uniform initialization. It's faster and safer than copy initialization.

      • Peter Baum

        1. Do I understand this correctly?  The compiler knows to pass an array by reference by default but doesn't do the same thing for a struct?

        2.1 Are you saying that you always have to assume that future extensions of an enum might not be consecutive?  One of the nice things about enums is that it makes things consecutive unless you go out of your way to do something different.

        2.2 It is trivial to know which character corresponds to which enum because except for the joker (used because enums default to a start at 0), the rank is consecutive if you assume ace is 1.  I created the string in a few seconds with complete confidence that the order was correct.

        2.3 Are you suggesting that another kind of card might be added to a deck of playing cards?  Even if it was, you are going to have to consider its rank and perhaps adjust the ranks regardless of the approach.  With a switch, you are then going to have to go in and make various adjustments as well.  I do not think it would be any more difficult with my approach.

        2.4 I get protection because of the use of SUIT_MAX and RANK_MAX.  I tried it out with an array that was too short, and it simply left a space there and such a mistake would be very easy to find.

        2.5 I did make a mistake though.  I should have used SUIT_MAX with the suitVal array.  I also added back in the &, assuming you are correct about structs.  This now makes the function as follows:

        2.6 The given solution has the disadvantages that it
           a) is 27 lines of code rather than 6,
           b) executes slower,
           c) uses more memory,
           d) doesn't create default behavior for an invalid case,
           e) and IMHO is aesthetically ugly.

        2.7 I do agree, however, that from a conceptual point of view, the solution is "more direct" and therefore simpler.

        3. Excellent point about uniform initialization.  I guess the issue revolves around the use of evolving features of CPP.  Should a programmer worry about code that gets moved to compilers that haven’t implemented the latest features of a language?  In any case, I corrected my routine based on the fact that my compiler accepts uniform initialization.  Thank you.

        • nascardriver

          1. Arrays are passed by pointer, because C-style arrays are nothing but a pointer (with size information).

          2.1 Enums will always be numbered consecutively, we talked about this somewhere before. The problem is that someone could manually change an enumerator's value which will cause your program to break if you rely on consecutive enumerators. If you say that you're never going to let anyone else work on your code and your never going to edit the enum, that's fine, I don't do that.

          2.2 It's easy in this case, because the cards are based on a real world example that's known by everyone who played cards. Again, if you think this assumption is ok, do it, I don't.

          2.3 Yes, another card might be added. I think updating a switch is easier to update than a string, because you have the correspondence of enumerator and character right in front of you whereas with a string you'd have to count characters or check in between which characters the new character should go.

          2.4 We're talking about different things then

          2.5 You used RANK_MAX again, but you're right, I didn't notice it in your submission.

          2.6
          a) Correct
          b) Correct, if compiler optimization is disabled
          c) Correct, because the array doesn't include an out-of-range check
          d) Mind giving an example how the switch doesn't have default behavior but the array does? I'd say it's the other way around.

          3.0 You're free to assume C++ version compatibility. Just don't use language extensions.

          Another note: Prefer 'constexpr' over 'const'. It does everything 'const' does but allows the constant to be used in 'constexpr' functions.

  • Peter Baum

    Problems with solution 3

    1. There is no indication by the name or comments that the swap routine will only work with int parameters.
    2. We learned very early in the lessons not to put constants like the 8 in the a==8 test in the code.
    3. One possibly approach is to print the values of a and b twice, once before and once after a call to swap:

    • nascardriver

      Hi Peter!

      @swap only takes ints, templates haven't been covered yet. There's no need to include the parameter types in the function name.

      Line 6, 7: I said I won't point this out, but there's absolutely no reason not to initialize @temp with @i1 in this case.
      Line 10: You don't need to return at the end of a void

      • Peter Baum

        Regarding the parameter type in the name: it doesn't hurt and I thought it was the kind of defensive programming you recommended.

        I agree about the initialization of temp.  Great improvement.

        I know you don't return a value with void, but it does emphasize when the function ends.  So you are saying you believe it is preferable not to use the return statement?

        • nascardriver

          > So you are saying you believe it is preferable not to use the return statement?
          I've never seen it done and I've never used it this way myself. If your code isn't formatted terribly it's easy enough to see where the function ends. Of course you can use 'return' the exit a void prematurely, I just wouldn't do so at the end of the function.

  • Peter Baum

    In anticipating coding 6C I wanted to use the unicode symbols that produce suit symbols, rather than just letters like C, S, H, and D.  I can see the symbols when I enter the cpp code but can't get it to print properly under visual studio.  I've tried things like

    to no avail. Any suggestions?

    • nascardriver

      Hi Peter!

      I haven't worked with unicode so I can't give you a full explanation or promise this works for you. I've seen a recommendation for the ICU library ( http://site.icu-project.org/ ), because unicode support appears to vary between operating systems.

      I can use an @std::string and print the text without problems.

      Note that member functions of @std::string work with bytes. You'll get wrong results off of @std::string::length, sorting won't work, and so on.
      Try sticking to ascii characters in your code files.

      • Peter Baum

        That is interesting.  With Visual Studio under windows 10 I just get question marks.  What compiler are you using?

        • nascardriver

          compiler: g++ (Debian 8-20180414-1) 8.0.1 20180414
          terminal: xfce4-terminal

          Make sure your terminal/console/powershell/output is able to display the characters in question before wasting time trying to fix an unsolvable problem.

          • Peter Baum

            No problem there, the example given in the post (i.e., with a browser) displays fine.  No problem with javascript either.  Maybe someone using Visual Studio can help.

            • Alex

              On Windows, you can try the method suggested here: https://stackoverflow.com/a/9051543

              • Peter Baum

                All right Alex!!!! That works!!!

  • Peter Baum

    I have been working on Quiz 2, or rather, a version that is more realistic as explained in another post.  Although I have a crude version that works, what I really want to do is have a way to parse the input in a general way and then respond to that parsed input.  In particular, although I expect first name, last name, and grade, I realize that users might use spaces or tabs as separators, might hit the enter key prematurely, might make a mistake putting in the grade, might have a user with a middle initial, et cetera.  Ideally, all I should have to do is call a routine that returns a list of structures that give input values and their datatypes.  This has to be a very common programming task.  

    Now, of course, I can spend a lot of time and program a routine that will perform this task myself, but I thought the reason I am learning a higher-level language is because it will allow me to develop code quickly.  I expected to have to go to a library routine and find the routine that will solve this common programming task.  However, I assumed this would be easy.  Yet here I am at the end of chapter 6 and it is not obvious to me how to find such routines or even if they exist.  

    I ran into a similar problem previously with trying to format text and saw suggestions that the C routine printf() solved the problem very easily.  As someone on github wrote, “What is wrong with C++?”

    • nascardriver

      Hi Peter!

      You might find a function to separate user input by spaces/tab/enter in some higher-level programming or scripting language, but not in C++. C++ requires you to write a lot of functions by yourself. As for your out-of-order, might have more names problem, that's too specific to find a library for, you'll have to come up with something of your own.
      If you're learning C++ to write code quickly you took the wrong turn. C++ is a language that takes some time to get stuff done with, you'd be better of with Java/Scala/etc.

      > printf
      I don't see anything wrong with the *printf functions. They exist since C but I still find them very useful.

      • Peter Baum

        Hi nascardriver!

        I found some regex routines and tokenizers as part of the Boost library.  I guess CPP often eventually adopts Boost routines but do it (painfully) slowly.

        I don't mind writing lots of functions myself, but it is sad to find that I could have done it more quickly in assembly language!  I'm not interested in a language that is interpreted, just a language that is well designed and evolves gracefully.  So far I find CPP very disappointing.  I do, however, intend to slog through.

        The out of order problem would be easy to solve if I got back that token list with data type information.

  • Peter Baum

    ***Regarding Quiz item 2***

    I would like to suggest that the program specification for this quiz item be made more specific and hopefully more “realistic.”  Here are some suggestions for how this might be done.

    • The student names should allow for first and last names.

    • Rather than require the user to count all the names and enter this number (which could be potentially in error), have the names and grades entered and the computer calculate the number of students.

    • For this kind of application, you could allocate array elements for 100 or even 1000 students without any problems.  In other kinds of applications where more memory might be required, we could use std::vector and do more fancy kinds of memory allocation/deallocation.

    • Perhaps the user can indicate the end of the entry by hitting the enter key rather than entering text.  If so, it might be a good idea for the user to confirm that the list is done and if not, allow for the user to continue entering names and grades.

    • Report the number of students as part of the output.

    • Clarify how the user is to enter the names and grades.  Can the user enter both on the same line?  Is there a prompt for each?  Should there be a prompt if no number is entered?  If only a single name is entered?

    • There should probably be some kind of error checking on names and grades.

    We could take the approach that this kind of “quiz” is just an exercise, so the fact that it is not realistic is not an issue.  The other perspective is that it is the very complexity of realistic problems that the programmer needs practice in addressing.  Making the problem more specific also has the advantage of limiting some of the programming approaches that result from an underspecified problem.  That means that other solutions to the problem will be more relevant, and thus more educational.

    • Alex

      I appreciate the feedback.

      The point of the quizzes is to provide a quick way to assess whether you understand the more important aspects of the lessons. Extending the quizzes to turn them into more realistic programs is a great way to learn, and something I encourage you and all other readers to explore of your own volition.

  • Peter Baum

    I'm struggling with this very first quiz item.  It isn't that I didn't get my program to run.  It was that

    1) There are so many ways to write the first line of the function definition, such as

    or

    or

    and I must not have a good understanding of these alternatives, because I don't know which would be best under this or other circumstances.  Perhaps some of these alternatives could be discussed as part of the solution, along with the pros and cons.

    2) I was bother by the use of the enum.  It wasn't clear to me, for example, whether or not we should assume the items will always be numbered  consecutively.  Also, the solution gave
        

    but that didn't involve the enum, and so you had to know at the point where the array is defined what the enum values actually are.  That didn't seem right.  On the other hand, writing

    didn't seem very elegant either.

    • nascardriver

      Hi Peter!

      1)

      For passing an int pointer.

      For passing an array of a size known at compile-time.

      For passing an array of arbitrary size. There's usually a second parameter used to pass the size.

      The only difference is that the second version can be used with for-each-loops.

      2)

      > whether or not we should assume the items will always be numbered  consecutively
      Unless you're manually assigning a value to an enumerator they're numbered consecutively.
      Neither of the solutions is nice. My first idea of implementing an inventory is something along the lines of

      plus appropriate member functions. Of course there are many more ways of doing this.

      • Peter Baum

        Hi Nascardriver!

        Regarding item 1 (arrays as function parameters; for each etc.).  Your response moves us forward, and the most helpful statement was the one about using stated array dimensions when you want to use a for-each loop.  But where are the people that like to make up rules when I need them?  I want to know, as a simple example, when an array is a parameter, should I let it default to a call by reference or put in the &?  Maybe some of these choices are based on the algorithm I’m implementing, maybe the choices are based on the compiler I’m using, maybe the choice is based on how the program might be extended in the future.  If CPP is going to give me lots of choices and I want to use them properly, then I need further explanations about these choices.  The same for the declarations involving arrays.  When, for example, should I fix the array size so I can use a for each statement?  In other words, is it more important to use a for each or not to fix the array size?   I think I understand some of these choices, but there are many choices and they have complex consequences, so I’m not sure.  It would be helpful to have all this laid out as a kind of flow chart.  Right now, I’m just trying to pick something that works rather than being able to make the best choice.

        Regarding ** Unless you're manually assigning a value to an enumerator they're numbered consecutively.**
        I know, but the question is whether or not we should assume that they will be consecutive in the future.  How defensive should our programming be?  Where is the rule for this???

        Regarding your ItemType class.  Yes, this is the kind of thing I’m looking for.  It would be helpful, though, to have a complete solution that includes the appropriate member functions and an example of its use within a program.  Or maybe this is coming up in a later lesson?

        • nascardriver

          > should I let it default to a call by reference or put in the &?
          I don't understand what you mean by 'let it default to a call by reference'. Mind giving an example for both cases?

          > maybe the choices are based on the compiler I’m using
          No

          > When, for example, should I fix the array size so I can use a for each statement?
          When you know the array size at compile time and you're only using the function for that specific array size. For example the blackjack quiz in this lesson's quiz, you'll always have an array of 52 or what not cards so you might as well specify your array parameter to accept only that array.

          > In other words, is it more important to use a for each or not to fix the array size?
          Depends on the function you're writing, there's no general answer.

          > assume that they will be consecutive in the future
          According to the standard, enumerators are numbered consecutively. This won't change, because it would break old code. Still, don't use enums for complex arrays (I count the item example as complex).

          > Where is the rule for this?
          If there was a rule for this, it'd say "It's safe to assume this and you can use enums for array indexes", because Alex uses enums to index arrays.

          > It would be helpful, though, to have a complete solution
          Too much and too specific for learncpp. Look at open-source games if you want to see how things like these are implemented. I think Minecraft (Not open source but MCP does a great job disassembling it, and it's Java, but if you can read C++ you can read Java) uses the approach I showed above. Of course it's up to Alex to decide about writing a lesson for this, I'm not affiliated with learncpp.

          • Peter Baum

            regarding call by reference and &.  Here is a specific example of the kind of thing that confuses me.  You can define a function in two different ways, such as

            but the result is the same.  Assume, for example,

            I interpret this to mean that without the & there is going to be a call by reference anyway.  If so, then I need to know why I would choose one way to code this over the other and perhaps would like to know why there are two ways to do the same thing.

            • nascardriver

              • Peter Baum

                I'm not sure what you mean.  

                * With fn1 you say "no size information is passed" and with fn2 you say "size information is preserved."  But aren't both of these things true for both functions since the array is specified as having 3 members?

                * If something is passed by reference or passed by pointer, are not these the same thing?  If not, what is the difference?

                * If both these function behave the same way and the definition uses different parameter forms, one being an obvious reference using & and the other converted to a reference, is this not a potential source of confusion?

                • nascardriver

                  > since the array is specified as having 3 members?
                  The 3 in @fn1 doesn't have an effect, I should've mentioned that

                  I don't know why the first syntax is allowed. It doesn't even cause a compiler warning when passing an array of another size.

                  > If something is passed by reference or passed by pointer, are not these the same thing?
                  See lesson 7.3 and 7.4. It's basically the same thing.

                  > If both these function behave the same way
                  They don't. One accepts an arbitrary sized array, the other accepts a fixed size array. One let's you for-each-loop through the array, the other doesn't.

                  > the other converted to a reference
                  It's not a reference, it's a pointer.

                  Now that you made me think about it, it's weird that we have to use a reference to have size information. I'd prefer the syntax of @fn1 in my previous reply since there doesn't seem to be any other use in having a reference.

                • Peter Baum

                  At least I’m starting to understand the questions to ask (thank you).  So what I have to straighten out in my mind is

                  • What is the difference between being a reference and a parameter being passed by reference?
                  • Parameters can (apparently) be passed by value, reference, or pointer.  Value is simple; the value gets copied.  Are you saying that the words  being “passed by reference” and “being passed by pointer” have two implications:

                     1. the way the information is sent to the routine… in this case both are pointers and
                     2. whether or not size information from the caller is sent to the routine…by pointer no, by reference yes?

                  • What are the implications of adding [] or [3] as part of the parameter in a function definition?

                • nascardriver

                  > What is the difference between being a reference and a parameter being passed by reference?
                  There is non. A reference is basically a pointer with different syntax.

                  > two implications
                  Both are pointers, none of them actually pass the array size, but using the reference syntax allows you to use the size of the array. There's no need to pass the size alongside the array, because it's known at compile time and can directly be stored in the .text section inside the function.

                  > What are the implications of adding [] or [3] as part of the parameter in a function definition?
                  It implies that the function wants an array (of size 3), not a regular pointer. However, the caller could still pass a regular pointer.

  • radu f

    So, here's my solution to Blackjack Challenge (including the variable value for the ace and the draws).
    Also, I didn't use the condition to go only on and above 17 points for the dealerPoints. I think it's more competitive to ask another card until his score it's higher than the player (IF the player didn't lose the game yet).
    Can you show me the weaknesses from it?
    Many thanks!

    • nascardriver

      Hi radu!

      Gratz on solving the quiz!

      * Use enum class instead of enum
      * Use uniform initialization
      * Use a constant for your deck size or an alias for your deck type
      * Line 84: What do you mean?
      * @shuffleDeck: use ref.size() instead of hardcoding the size
      * @getCardValue: @points shouldn't be a reference
      * cases in switch statements don't need curly braces
      * Line 128, 131: Unnecessary brackets around (*cardPtr++)
      * Line 132: This should be split into multiple lines for readability
      * Line 145: Use std::numeric_limits<std::streamsize>::max() instead of 32767

      • radu f

        Thanks, nascardriver!

        * Line 84: "What do you mean?" - In Alex's solution, he used the permutation instead of swapping the values. I was wondering if there's a particular reason to use that solution, because, as far as I can understand, in terms of memory management, using std::swap prevent us from creating an unnecessary additional variable. Which brings me another question: is it std::swap slower in execution than the values permutation (because we have to access the utility header)? I guess memory management and execution time will be later discussed too...

        * @getCardValue: "@points shouldn't be a reference" - I used it considering "memory management" (and knowing that I'll not change the value of it inside the function). Are other reasons for not using it there? Later Edit: modifying the parameter in "const int &points" should be better, I guess.

        p.s. I'm aware that the spared memory for the both situations is almost insignificant, but, in order to build good habits I tried to minimize things 😉

        • nascardriver

          > In Alex's solution, he used the permutation instead of swapping the values.
          Use @std::swap. If there is a function is the standard namespace you shouldn't write it again.

          > is it std::swap slower in execution than the values permutation (because we have to access the utility header)?
          @std::swap is faster, because it's moving the values rather than copying them (Chapter 15). Including headers cannot slow down your program, all it can do is increase binary size (It shouldn't when building in release mode).

          > I used it considering "memory management"
          Standard sized data types (1,2,4,8 bytes) should be passed by value, passing them by reference might actually be slower (It shouldn't).

          > I'm aware that the spared memory for the both situations is almost insignificant, but, in order to build good habits I tried to minimize things
          That's a good thing. Memory/Storage consumption doesn't really matter on modern desktop computers, but who knows when you'll have to be working on an embedded system.

  • Burka Christopher

    I'm having a problem with the shuffle function in  my card game.It displays the cards, but I can not shuffle them.

  • Matt

    Holy cow.  I did not know what I was getting myself into when I stuck my head in this rabbit hole.  I think my code is complete (minus error checking for user inputs and coming up with a logical way to organize this into multiple files so it's not one huge wall of code).

    Thanks for the fun challenge!

    Regards,
    Matt

    • nascardriver

      Hi Matt!

      • Matt

        Thanks for your input!
        >You're using this size calculation a lot. Another indicator for declaring a constant for it.
        >Avoid evaluating code outside of functions. A constant holding the deck size would've been better.
        Couldn't agree more.  I actually declared a global variable for it and then later removed it because I thought I remembered "global variables are evil."  I'll review those lessons.

        >I have no idea how blackjack works. Shouldn't this be pScore -= 10 * pAces
        Actually no, the goal is for the score to be as high as possible without going over 21.  Your way of doing it would be akin to making every ace's value worth 1.  We want them to be worth 11 unless our score is over 21, in which case we will take _one_ of our aces and reduce its value from 11 to 1 to bring our score back below the 21 threshold so we don't bust.  We will only reduce the next ace (assuming we have another) if our score goes over 21 again.

        >Why the crazy dereferencing? // cardPtr->rank
        My head was spinning at this point in the code, I knew there had to be a better way to do it but when I finally found a syntax that 'worked' I just left it alone.  Thanks for showing me the right way.

        >Duplicate of @dealToDealer
        That's smart, I'd have to mess with the couts a bit but it certainly could be reduced to just a deal() function

        >You have enabled line wrapping, I'm breaking it. I prefer longer lines if it makes the code easier to read. I think wrapping the lines is preferred.
        I've actually been breaking my lines manually (trying to keep each line of code short enough that it's legible on smaller screens) but sometimes it just gets unreadable when a function declaration is really long.  I'm still working on making long code lines legible and trying to pick good places to break them.

        Thanks again for the help!
        Matt

        • nascardriver

          > I remembered "global variables are evil."
          They are, but sometimes your need them. The things I can thing of right now to avoid a global variable while still maintaining global accessibility:
          - Put globals in a namespace
          - Put globals as static members in a class
          - Use a singleton class (Not applicable in your situation)

  • Silviu

    can you explain a little bit more on this part of the code ? Thank you.

    • nascardriver

      Hi Silviu!

      If this doesn't help you you might want to print out @suit and @rank inside the loop to get a better understanding of what's happening.

      • Silviu

        thank you for the help .

        Hint: Use static_cast if you need to convert an integer into an enumerated type // this is from Alex
        I don't know how exactly the conversion is done here : can you give me one example with the integer in this case, i mean don't get me wrong i know to convert an int to a float , or a int to a char. I know suit,rank is the part that has it as integer and CardSuit,CardRank is the enumerated type and then somehow puts it in deck ?

        Here it shouldn't be "==" ? i tested with equal and works...

        playerTotal being initialized with 0.
        Here i just want to be sure , playerTotal= gets a card value from the function lets say 2 and playerTotal= 0+2.
        and in the next line playerTotal=2+ gets another card value from the function . playerTotal= 2+ lets say 3 =5.
        then it goes in the while with the sum of 5. Am i right ?

        getCardValue is function with the parameter (*cardPtr that is pointing to the value and ++). That "++" is there for ? i know it means= evaluate the variable and then increments it, but why does it need to ?

        Thank you .

        • nascardriver

          > Cast

          > Here it shouldn't be "==" ?
          No, you're asking the user for an input until they enter either 'h' or 's'. So as long as their input is not 'h' or 's' you keep looping.

          > i tested with equal and works
          Because you now have

          choice can't have two values at the same time. No matter what you enter, the loop will stop.

          > then it goes in the while with the sum of 5. Am i right ?
          You are right.

          > i'm kinda lost here

          > That "++" is there for ?
          Let's split that line into two

          • Silviu

            Thank you for the help. This one it was a hard chapter to dig in and i'm gonna read them again so i can clarify what i'v learned till now.

            I need to exercise more on these things, but thank you for helping .

  • Matt

    I tried to use my enumerated classes to iterate through the deck array but when I attempt to increment the index I get this error:

    "this operation on an enumerated type requires an applicable user-defined operator function"

    I'm not sure I know what that means.  Is there some way I can write an additional function that defines how the ++ operator is supposed to work with enumerated types?

    Here's what I was trying to do:

    This is what I ended up with, but honestly I think I'd prefer magic numbers to using static_cast so much in my loops.

    • nascardriver

      Hi Matt!

      > prefer magic numbers to using static_cast
      No!

      You can define an operator++ for your enum class.

      Keep in mind that enum values aren't always contiguous:

      References
      https://stackoverflow.com/questions/15450914/incrementation-and-decrementation-of-enum-class
      https://stackoverflow.com/questions/15451382/implementation-of-operators-for-enum-class
      The vanilla switch is probably the easiest https://stackoverflow.com/a/15456011/9364954

      • Matt

        Wow, that's exactly what I was looking for!  Alex, I think discussing how to iterate over enum classes would be a valuable lesson or sublesson for your site...my apologies if it already exists.  One of the best things about enums (as far as I can tell, currently), is that it allows me to use words instead of magic numbers in my code.  Hopefully, when reading the following function, the reader would be able to understand how the loop is going to work even if they didn't completely understand how the Card struct was laid out.

        In plain words, to me, it means: "Starting at the ACE of CLUBS, assign one of each rank of clubs, then repeat for each suit of cards." Defining an incremental operator ++ or -- for the enum class allows me to remain consistent in my naming pattern so I don't have to static_cast within the loop definition, and I personally think that's a concept worthy of your site!

        Edit: I've been doing further research (trying to understand the syntax in nascardriver's example of "defining an operator++ for your enum class."  Based on what I understand of the following url, operator++ is defined in a "class" of its own.  ( ref: http://en.cppreference.com/w/cpp/language/operator_incdec ).  In that case, I guess the syntax of this whole scenario will make more sense when I get to the lessons on classes.

        For now, this is still illegible code to me.  It makes sense what it is doing inside of the brackets, but this "function" or whatever it is doesn't make sense.

        I'll keep marching forwards!  It will all come together eventually.

        Best regards,
        Matt

  • Matt

    I've completed quizzes 1 - 4, I'll have to get to the blackjack tomorrow!

    Quiz 1:

    Quiz 2: