CSC 101 Lecture Notes Week 7, Part 2

CSC 101 Lecture Notes Week 7, Part 2
Character Strings as Arrays




  1. Reading
    1. Chapter 12, pp. 668-678
    2. Chapter 13, pp. 707-724

  2. Overview
    1. In previous assignments, we have used character strings in a limited fashion.
    2. For programming assignments 5 and 6, we will need to use some more advanced forms of string processing.
    3. The key to understanding character string processing is to realize that a character string is an array of characters.
      1. This means we can assign strings to array variables.
      2. It further means that we can access individual characters within a string by normal array indexing.

  3. Working with character strings (textbook pp. 668-678)
    1. As noted above, a character string is standard array, with char as its element type.
    2. One bit of specialized processing that C++ does with strings is null termination.
      1. This means that after the last character of any string, C++ uses a null character '\0' to mark the end of the string.
      2. Consider the following example:
        ////
        //
        // This program reads a character string from the terminal and outputs the
        // string characters back to the terminal, one by one.
        //
        ////
        
        #include <iostream.h>
        
        int main() {
            char string_value[11];      // Holds up to 10 chars, plus null termination
            int i;                      // Loop and array index
        
            //
            // Prompt for and read a value into the string variable.
            //
            cout << "Input a string up to 10 characters long: ";
            cin >> string_value;
        
            //
            // Output the individual chars of the string variable one by one.
            //
            cout << "The significant chars of the string value are: " << endl;
            for (i = 0 ; string_value[i] != '\0' ; i++) {
                cout << "    string_value[" << i << "] = " << string_value[i] << endl;
            }
        
            return 0;
        }
        
      3. Here is a sample run:
        Input a string up to 10 characters long: hi
        The significant chars of the string value are:
            string_value[0] = h
            string_value[1] = i
        
      4. This shows how C++ automatically puts a null character after this last char of a string when a string value is assigned to a string variable.
      5. The example also illustrates how to access the individual characters of a string via normal array operations.
    3. String library functions (pp. 676 - 677).
      1. Through the library string.h, C++ provides the following string processing functions:
        Function Description
        int strlen(char* str) Return the number of characters in str, excluding the null termination.
        int strcmp(char* str1, char* str2) Compare str1 with str2, returning 0 if they are lexically, a negative value if str1 is lexically less than str2, and a positive value if st1 is lexically greater than str2.
        void strcpy(char* to_str, char* from_str) Copy all of the characters from from_str, including the null, into to_str; from_str must be large enough to hold the number of chars copied.
      2. The strlen function is used whenever you need to determine the length of a character string.
      3. strcmp is used to compare two strings, since as noted earlier, the normal equality operator '==' does not work properly to compare arrays elementwise.
      4. Similarly, strcpy is used to assign one string to another, since the normal assignment operator '=' does not work properly to assign arrays elementwise.

  4. Arrays of strings, i.e., arrays of arrays (pp. 707 - 724).
    1. While an array of arrays may sound like a major new concept, it's really quite natural.
      1. An array can contain any type of element.
      2. E.g., an array of integers contains numeric values.
      3. An array of characters contains individual character values.
      4. An array of strings contains string values, and it so happens that string is itself and array; hence an array of strings is an array of arrays.
    2. You don't really need to understand all of the details of two dimensional arrays to understand arrays of strings.
    3. You do need to understand how an array of strings is declared and accessed; this is illustrated in the example given below.

  5. Further examples of string processing.
    1. The example below illustrates further the concepts of C++ string processing, as well as some of the kinds of processing that you will do in assignments 5 and 6.
    2. Note that the example program is broken up into more than one file; we will discuss details of how and why this is done next week.
    3. File card-play.h:
      ////
      //
      // This file declares functions that illustrate the kinds of card-related
      // processing that will be done in programmming assignments 5 and 6.
      //
      // NOTE: this is a C++ header file, containing only function declarations, but
      //       no definitions.  The companion file card-play.cpp, q.v., contains the
      //       the definitions of the functions declared here.
      //
      ////
      
      #ifndef card_play_included
      #define card_play_included
      
      #include "Boolean.h"
      #include <fstream.h>
      
      const int DECK_SIZE = 52;       // Number of cards in a deck
      const int CARD_STR_LEN = 4;     // Number of chars in the string rep of a card
      
      
      ////
      //
      // Function ReadCardAsString inputs a single card from the terminal and returns
      // the card as a string in the reference parameter.  The format of the card is
      // as described in the program 5 writeup.  This function does no validity
      // checking of the card spelling, it simply inputs it as a string of two or
      // three characters.
      //
      ////
      void ReadCardAsString(
          char card[CARD_STR_LEN]                // Returned card string
      );
      
      
      ////
      //
      // Function ReadCardAsIntAndChar inputs a single card from the terminal and
      // returns the card as a two-part value in the face_value and suit reference
      // parameters.  The format of the card is as described in the program 5
      // writeup.  The face_value is an integer between 1 and 13.  The values 2
      // through 10 represent the face value directly.  The face value 1 is for an
      // Ace, 11 for a Jack, 12 for a Queen, and 13 for a King.  The suit is one of
      // the characters 'S', 'H', 'D', or 'C'.
      //
      // This function performs validity checking of the input.  Specifically, the
      // first one or two characters must be a legal face value and the last
      // character must be a legal suit.  If the input is legal, the function returns
      // TRUE, otherwise FALSE.
      //
      ////
      Boolean ReadCardAsIntAndChar(
          int& face_value,            // Returned face value
          char& suit                  // Returned suit
      );
      
      ////
      //
      // Function ReadFaceValue does the face value processing for function
      // ReadCardAsIntOrChar, from which it is called.
      //
      ////
      void ReadFaceValue(
          int& face_value             // Returned face value
      );
      
      ////
      //
      // Function ReadSuit does the suit processing for function ReadCardAsIntOrChar,
      // from which it is called.
      //
      ////
      void ReadSuit(
          char& suit                  // Returned suit
      );
      
      ////
      //
      // Function ReadDeckFromFile reads a full card deck from the given input file.
      // The file is assumed to contain DECK_SIZE legal cards.  The deck is returned
      // as an array of DECK_SIZE character strings in the deck reference parameter.
      //
      ////
      void ReadDeckFromFile(
          ifstream& deck_file,                    // Input file
          char deck[DECK_SIZE][CARD_STR_LEN]      // Returned deck of cards
                //  ^^^^^^^^^  ^^^^^^^^^^^^
                //  ^^^^^^^^^  ^^^^^^^^^^^^ CARD_STR_LEN is the size of each array
                //                          element (a card string)
                //  ^^^^^^^^^
                //  ^^^^^^^^^ DECK_SIZE is the size of the deck array
      );
      
      ////
      //
      // Function DumpDeck simply dumps a deck of 52 cards to the terminal.
      //
      ////
      void DumpDeck(char deck[DECK_SIZE][CARD_STR_LEN]);
      
      #endif
      

    4. File card-play.cpp:
      ////
      //
      // This file contains function definitions for the functions declared in
      // card-play.h, q.v.
      //
      // NOTE: this file has no main function.  It is designed to be compiled with a
      // separate test driver file.  For example, to test the card reading functions
      // in this file, it is compiled with a separate test driver file as follows:
      //
      //     CC test-card-reads.cpp card-play.cpp -o test-card-reads
      //
      // File test-card-reads.cpp, q.v., contains a main driver function that calls
      // the card reading functions in this file.
      //
      ////
      
      #include "card-play.h"
      #include <iostream.h>
      #include <fstream.h>
      
      
      void ReadCardAsString(char card[CARD_STR_LEN]) {
          cout << "Input a card: ";
          cin >> card;
      }
      
      Boolean ReadCardAsIntAndChar(int& face_value, char& suit) {
      
          cout << "Input a card: ";
      
          //
          // Initialize the face value to 0 and suit to ' '.  If these initial values
          // are not changed, then an input error was detected.
          //
          face_value = 0;
          suit = ' ';
      
          //
          // Input the face value.
          //
          ReadFaceValue(face_value);
      
          //
          // If a legal face value was read, proceed to input the suit character.
          //
          if (face_value != 0) {
              ReadSuit(suit);
          }
      
          //
          // Ignore any remaining input chars up to the next newline.
          //
          cin.ignore(100, '\n');
      
          //
          // Return true if face value is non-zero and suit is non-blank, false
          // otherwise.
          //
          if ((face_value != 0) && (suit != ' ')) {
              return TRUE;
          }
          else {
              return FALSE;
          }
      }
      
      void ReadFaceValue(int& face_value) {
      
          char in_char;               // Temporary input char
      
          //
          // Input the next character from the terminal.
          //
          cin >> in_char;
      
          //
          // Read the next character from the terminal, and check it as legal face
          // value.  Note the trick for values 2 through 9, which subtracts the ASCII
          // value of the character '0' to obtain the integer value of the character.
      
          //
          // If the char is between 2 and 9, compute its value with a cute trick.
          // Viz., subtract the value of character '0' from the input char value.
          // This will convert the digit character value to its numeric integer
          // value.  See pages 518-520, and page A30 of the textbook for more info.
          //
          if ((in_char >= '2') && (in_char <= '9')) {
              face_value = in_char - '0';
          }
      
          //
          // If the input char is for an ace, jack, queen, or king, make its face
          // value 1, 11, 12, or 13, respectively.
          //
          else if (in_char == 'A') {
              face_value = 1;
          }
          else if (in_char == 'J') {
              face_value = 11;
          }
          else if (in_char == 'Q') {
              face_value = 12;
          }
          else if (in_char == 'K') {
              face_value = 13;
          }
      
          //
          // If the input char is a '1', make sure the next char is a '0', and make
          // the face value 10.
          //
          else if (in_char == '1') {
              cin >> in_char;
              if (in_char == '0') {
                  face_value = 10;
              }
          }
      
          //
          // Check that a legal face value was read.  If not, output an error
          // message.
          //
          if (face_value == 0) {
              cout << "Illegal face value for card." << endl;
          }
      }
      
      void ReadSuit(char& suit) {
      
          char in_char;               // Temporary input char
      
          //
          // Input the next character from the terminal.
          //
          cin >> in_char;
      
          //
          // Check that the suit char is legal and output an error message if
          // not.
          //
          if ((in_char == 'C') || (in_char == 'D') ||
                  (in_char == 'H') || (in_char == 'S')) {
              suit = in_char;
          }
          else {
              cout << "Illegal suit for card." << endl;
          }
      }
      
      void ReadDeckFromFile(ifstream& deck_file,
              char deck[DECK_SIZE][CARD_STR_LEN]) {
          int i;
      
          //
          // Loop through the input file, putting the file data values into
          // successive elements of the deck array.
          //
          for (i = 0; deck_file; i++) {
              deck_file >> deck[i];
          }
      }
      
      void DumpDeck(char deck[DECK_SIZE][CARD_STR_LEN]) {
          int i;
      
          //
          // Loop through the deck, outputting each element to the terminal.
          //
          for (i = 0; i < DECK_SIZE; i++) {
              cout << "Card " << i << ": " << deck[i] << endl;
          }
      }
      

    5. File card-play-basic-tests.cpp:
      ////
      //
      // This program performs some basic tests on the functions defined in
      // card-play.cpp, q.v.
      //
      // NOTE: these tests are not exhaustive, they just do some basics.  More
      // thorough testing is done in other testing programs, such as
      // card-read-tests.cpp, q.v.
      //
      ////
      
      #include "card-play.h"
      #include <iostream.h>
      #include <fstream.h>
      
      
      const int MAX_HAND_SIZE = 20;   // Maximum number of cards in any hand
      
      int main() {
      
          //
          // Declare some variable to work with.
          //
          char deck[DECK_SIZE][CARD_STR_LEN];              // Basic deck
          char players_hand[MAX_HAND_SIZE][CARD_STR_LEN];  // Sample hand of cards
          char dealers_hand[MAX_HAND_SIZE][CARD_STR_LEN];  //    "    "   "    "
          ifstream deck_file;                              // File containing cards
          char card[CARD_STR_LEN];                         // Sample card as string
          int card_face_value;                             // Sample card as int
          char card_suit;                                  //   and char
      
          //
          // Read a card from the terminal as a string.
          //
          ReadCardAsString(card);
          cout << "Card read as string: " << card << endl;
      
          //
          // Read a card from the terminal as an int and char.
          //
          ReadCardAsIntAndChar(card_face_value, card_suit);
          cout << "Card read as face value and suit: "
               << card_face_value << ", " << card_suit << endl;
      
      
          //
          // Open the sample card deck file, read it in, and dump it back out.
          //
          deck_file.open("fulldeck");
          ReadDeckFromFile(deck_file, deck);
          DumpDeck(deck);
      
          //
          // Perform some additional tests on the card handling functions.
          //
          cout << "Input a card value: ";
          cin >> players_hand[0];
      
          cout << "Value just put in players_hand[0] = " << players_hand[0] << endl;
      
          cout << "Size of dealer's and player's hands (should be 20*4): "
               << sizeof(dealers_hand) << ", " << sizeof(players_hand) << endl;
      
          cout << "Size of a hand elem: " << sizeof(players_hand[0]) << endl;
      
          return 0;
      }
      




    index | lectures | labs | handouts | assignments | solutions | grades | help