CS 111 Assignment 6

Answers to practice problems are here.
  1. Files to print out and bring to lecture and recitation
  2. Preparations before you begin your homework
  3. Practice problems
  4. Assigned programming problems
  5. Preparing to hand in your homework

For information about the due dates, including late dates and extra-credit early due dates, please see Homework policies and due dates.


  1. Files to print out and bring to lecture and recitation

    Below are tutorials and example programs and data files. Please make printouts of these and bring them with you to both lecture and recitation. However, please do NOT print them out in an on-campus lab. (On-campus printers are to be used only for your homework, i.e. for files YOU wrote.) If you do not have a computer at home, with a printer, ask a friend or classmate to print out copies of the following files for you.


  2. Preparations before you begin your homework

    On forbin, create a directory named hw06 inside your homework directory. Change your present working directory to hw06 and then copy into it the example files for this homework assignment, by typing, at the "forbin>" prompt:

       cp ~nixon/cs111/hw06/* .
    

    Please do NOT copy these files into your home directory, to avoid cluttering your home directory. If you inadvertantly copied them into your home directory, move them out using the mv command. Be very careful about deleting anything in your home directory, to avoid inadvertantly deleting your hidden files (.login, .cshrc, .profile, etc.).


  3. Practice problems

    1. In textUtility.cpp, the function isNaturalNumber is now a stub. (For more about stubs, see the section on "stubs and drivers" in the totorial on String class objects as parameters to functions . Replace the stub with a function which actually does what it is supposed to do, according to the comment above the function.

      The function must check two things: (1) whether the string contains at least one character (i.e., whether its length is at least 1) and (2) whether all the string's characters are non-digit characters. Note that checking whether all the string's characters are digit characters can be accomplished by checking whether the string contains any non-digit characters. You may use a technique similar to the loop in the isAsciiControl function which checks whether a string contains any control characters. To check whether the character at position i in string text is a non-digit, you may use a negated call to the isAsciiDigit function (defined in textUtility.cpp) as follows:

            if ( ! isAsciiDigit(text[i]) )
      

      Don't blindly copy the isAsciiControl function. Be careful about deciding the circumstances under which your isNaturalNumber function should return true, vs. the circumstances under which it returns false. Remember that a string can represent a natural number only if it contains NO non-digit characters, NOT if your function has succeeded in finding a non-digit character.

      However, if a string contains no non-digit characters, that in itself is not sufficient to guarantee that the string represents a natural number. A string which contains no non-digit characters MIGHT represent a natural number. Itt might also be an empty string, which does not represent a natural number, even though it contains no non-digit characters (because it contains no characters at all). Your function will need to treat the empty string as a special case. It is recommended that your function check for an empty string (and return false if the string is empty) BEFORE the function begins testing whether a non-empty string contains non-degit characters.).

      To test your function, compile the driver program testIsNaturalNumber1.cpp by typing:

         g++ testIsNaturalNumber1.cpp textUtility.cpp
      

      and run it, entering various test strings. First, check the performance of your function for various nonempty strings, some of which represent natural numbers and some of which do not. The strings you check should include the following:

         1234567890
         123456789012345678901234567890
         09
         0
         9
         /
         :
         a2
         2a
      

      Note that '/' is the character whose ASCII/Unicode value is one less than that of the digit '0', and ':' is the character whose ASCII/Unicode value is one greater than that of the digit '9'. When testing a program, it is always a good idea to check boundary cases such as these.

      Your function should recognize very long purely-numeric strings, such as the second one on the list above, as representing natural numbers.

      Now run testIsNaturalNumber1.cpp again, entering an empty string. When used with an empty string, the program should state that it does NOT represent a natural number.

      Then test your function further by compiling another driver program testIsNaturalNumber2.cpp by typing:

         g++ testIsNaturalNumber2.cpp textUtility.cpp
      

      and run it.

    2. In textUtility.cpp, write function isInteger with the following comment and heading:

      /*
       * bool isInteger(const string& text)
       *
       * Tests whether the specified string represents
       * an integer.  A string represents an integer if,
       * and only if, it consists of a string representing
       * a natural number possibly prefixed by an optional
       * leading minus sign. 
       *
       * Parameter:
       *    text -  the string to be tested.
       *
       * Returns:
       *    true if text represents an integer,
       *    false otherwise.
       */
      bool isInteger(const string& text)
      

      and put a suitable declaration (prototype) in the header file textUtility.h. In textUtility.cpp, define the function so that it behaves as advertised in the comment. It should recognize, as representing integers, all strings that are recognized as natural numbers by the function isNaturalNumber, plus all strings that consist of a leading minus sign (-) followed by at least one digit character and no non-digit characters.

      Note that the comment does NOT specify an allowed range of the integer. The function should return true for a string representing any integer, no matter how big.

      Before testing for a leading minus sign, your function should first check whether the string is empty. Otherwise, your function might try to access the nonexistent first character in an empty string, resulting in an unpredicatable runtime error.

      If the string begins with a leading minus sign, you will then want to call isNaturalNumber for a substring consisting of the all the characters in the original string EXCEPT for the leading minus sign. A substring that skips the first character of string text could be generated as follows:

            string restOfText = text.substr(1, text.length()-1);
      

      (For more about the substr function, review the tutorial on string functions in Assignment 4.)

      If the string text does NOT begin with a leading minus sign, then isNaturalNumber should be called for text itself.

      To test your function, compile driver program testIsInteger.cpp by typing:

         g++ testIsInteger.cpp textUtility.cpp
      

      and run it.

      Make sure your function works correctly for all the cases tested by the program.

    3. In textUtility.cpp, write function isForbinInt with the following comment and heading:

      /*
       * bool isForbinInt(const string& text)
       *
       * Tests whether the specified string represents
       * a value of type int on forbin.  A string represents
       * such a value if, and only if, it consists of a
       * string representing an integer and that integer is
       * within the int range on forbin, i.e. within the
       * range -2147483648 to 2147483647, inclusive.
       *
       * Parameter:
       *    text -  the string to be tested.
       *
       * Returns:
       *    true if text represents an int on forbin.
       *    false otherwise.
       */
      bool isForbinInt(const string& text)
      

      and put a suitable declaration (prototype) in the header file textUtility.h. In textUtility.cpp, define the function so that it behaves as advertised in the comment.

      It is recommended that begin by calling your isInteger function to determine whether the string represents an integer. If the string does not represent an integer, then it obviously does not represent an integer within the int range on forbin, either. So, if your call to isInteger returns false, then isForbinInt can go ahead and return false too. Only if the string represents an integer do you need to concern yourself with whether the represented integer is within the appropriate range.

      To determine whether the represented integer is within the appropriate range, you CANNOT simply then convert it to int (say, by calling the parseNaturalNumber function) and then test whether the value is within range. If the value is not within range, it will not be converted correctly to an int. (Any resulting int WILL be within the int range, whether or not the number represented by the original string was within the int range.)

      Instead, you will need to do comparisons of the strings themselves to strings representing the extreme values of the forbin int range. First, review the information about comparison of strings in the tutorial More about characters and strings.

      Before you can compare strings of digit characters, you'll need to strip the leading minus sign, if any, using either the substr function or the erase function. (For information about the erase function, see the tutorial on string functions in Assignment 4.) When removing the minus sign, do not modify the contents of the string text itself. Remember that text has been declared const, which means it cannot be changed. Any attempt to change it will give you a syntax error. So, instead of changing text itself, declare a string local variable which will be a copy of text. You can modify the local variable at will.

      As explained in the Assignment 6 tutorial More about characters and strings, a lexicographical comparison of strings representing natural numbers corresponds to a numeric comparison of the represented numbers only if the two numbers have the same number of digits. So, before you do the lexicographical comparison, you'll first need to check the lengths. But before you can meaninfully check the length, you'll first need to remove all leading zeroes, if any. Again, do not remove leading zeroes from text itself, but only from a local variable copy.

      The numbers at the limits of the int range, -2147483648 to 2147483647, each have 10 digits. So, after you've removed the leading minus sign and leading zeroes, if any, you can tell that the represented integer is in the int range if its length is less than 10, and you can tell that it is NOT in the int range if its length is greater than 10. If its length is equal to 10, then you'll need to do the lexicographical comparison.

      However, to know the exact string to which we need to do our lexicographical comparison ("2147483648" or "2147483647"), we need to know whether our original string was supposed to represent a negative number. To that end, you might want to use a boolean variable to keep track of whether original string text began with a leading minus sign, before you removed it.

      Plan your algorithm carefully in light of all the above considerations.

      Test your function using the driver program testIsForbinInt.cpp. (Remember to compile it together with textUtility.cpp.)

    4. In textUtility.cpp, write function parseForbinInt with the following comment and heading:

      /*
       * bool parseForbinInt(const string& text,
       *                     int& number)
       *
       * Converts a string to an int value, if the
       * string represents an integer within forbin's
       * int range, i.e. within the range
       * -2147483648 to 2147483647, inclusive.
       *
       * Parameters:
       *    text - the string to be converted
       *    number -  the intended int value.
       *       Precondition: none
       *       Postcondition:  number is the intended
       *          integer value represented by the string,
       *          if the string represents a valid forbin
       *          int value.  Otherwise, number is
       *          unchanged.
       *
       * Returns:
       *    true if a non-negative integer was successfully
       *    read from text, false otherwise.
       */
      bool parseForbinInt(const string& text,
                          int& number)
      

      and put a suitable declaration (prototype) in the header file textUtility.h. In textUtility.cpp, define the function so that it behaves as advertised in the comment.

      It is recommended that you begin the body of the parseForbinInt function by calling isForbinInt to determine whether the string represents a valid forbin int value. If it doesn't, then the parseForbinInt function does not need to do anything further, except to return false. Only if the string does represent a valid integer does it make sense to bother doing the actual conversion.

      Then, to do the actual conversion, it is recommended that you call parseNaturalNumber. But first, check whether the string begins with a leading minus sign. If so, a substring should be generated without the leading minus sign, so that parseNaturalNumber can be called for the substring, which will consist of digit characters only.

      Then, make sure the resulting integer value ends up with the correct sign, by subtracting it from zero if the original string began with a leading minus sign. You may want to use a boolean variable to keep track of this.

      Test your function using the driver program testParseForbinInt.cpp. Remember to compile it together with textUtility.cpp.

      Make sure your function works correctly for all values, including -2147483648, the low end of the range.


    5. In textUtility2.cpp, there is a stub for a C-string version of the isNaturalNumber function, of which you wrote a string class object version in Assignment 6. Replace the stub with a function body which actually does the specified job.

      Before you begin, make sure you have the latest versions of textUtility2.cpp and textUtility2.h, which contain the newly-added isInteger function.

      Also before you begin, read the Tutorial on one-dimensional arrays, especially the last section, on "C-strings as parameters to functions." It will contain some important clues.

      When you are finished writing the function, test it via the driver program testIsNaturalNumberC.cpp, which you can compile by typing:

         g++ testIsNaturalNumberC.cpp textUtility2.cpp
      

      Once you have gotten the isNaturalNumber function to work correctly, the isInteger function -- which calls isNaturalNumber -- should also work correctly. Test the isInteger function via testIsIntegerC.cpp.


    6. In textUtility2.cpp, write the function isForbinInt with the following comment and heading:

      /*
       * bool isForbinInt(const char text[])
       *
       * Tests whether the specified string represents
       * a value of type int on forbin.  A string represents
       * such a value if, and only if, it consists of a
       * string representing an integer and that integer is
       * within the int range on forbin, i.e. within the
       * range -2147483648 to 2147483647, inclusive.
       *
       * Parameter:
       *    text -  the string to be tested.
       *
       * Returns:
       *    true if text represents an int on forbin.
       *    false otherwise.
       */
      bool isForbinInt(const char text[])
      

      and put a suitable declaration (prototype) in header file textUtility2.h. In textUtility2.cpp, define the function so that it behaves as advertised in the comment.

      It is recommended that begin by calling the isInteger function to determine whether the string represents an integer. If the string does not represent an integer, then it obviously does not represent an integer within the int range on forbin, either. So, if your call to isInteger returns false, then isForbinInt can go ahead and return false too. Only if the string represents an integer do you need to concern yourself with whether the represented integer is within the appropriate range.

      Then, as in Assignment 6, you will need to (1) obtain a substring which does not contain the leading minus sign, if any, and which also does not contain any leading zeroes, (2) test the length of that substring, and (3) perform lexicographical comparison of the substring to C-string literals representing the extreme values of the range.

      To obtain the substring, use pointer arithmetic, as discussed in the Tutorial on one-dimensional arrays. See especially the last two sections, "Still more about arrays as parameters" and "C-strings as parameters to functions."

      To do the lexicographical comparison of strings, do NOT use relational operators (<, >, <=, >=, ==, and !=), which perform a lexicographical comparison only if at least one of the strings is a C++ string class object. To compare two C-strings, call the compare function defined in textUtility2.cpp.

      When finished writing your isForbinInt function, test it via the driver program testIsForbinIntC.cpp.


    7. In textUtility2.cpp, write the function parseForbinInt with the following comment and heading:

      /*
       * bool parseForbinInt(const char text[],
       *                     int& number)
       *
       * Converts a string to an int value, if the
       * string represents an integer within forbin's
       * int range, i.e. within the range
       * -2147483648 to 2147483647, inclusive.
       *
       * Parameters:
       *    text - the string to be converted
       *    number -  the intended int value.
       *       Precondition: none
       *       Postcondition:  number is the intended
       *          integer value represented by the string,
       *          if the string represents a valid forbin
       *          int value.  Otherwise, number is
       *          unchanged.
       *
       * Returns:
       *    true if a non-negative integer was successfully
       *    read from text, false otherwise.
       */
      bool parseForbinInt(const char text[],
                          int& number)
      

      and put a suitable declaration (prototype) in header file textUtility2.h. In textUtility2.cpp, define the function so that it behaves as advertised in the comment.

      As in Assignment 6, it is recommended that you use calls to the functions isForbinInt and parseNaturalNumber.

      When finished writing your parseForbinInt function, test it via the driver program testParseForbinIntC.cpp.


  4. Assigned programming problems

    Re-write the your Assignment 4 program as a program involving multiple functions rather than one big long main function, as specified below. The new program should have the filename atm2.cpp and should use the same input data files as the Assignment 4 program.

    Your program should behave exactly the same as the program specified in Assignment 4, except that the name of the data file should not be entered as a command-line argument. Instead, the program should begin by prompting the user for the name of the data file. (This will be necessary in order for the script file to work.)

    Your program should define the following functions, in addition to the main function:

    • All the functions that you developed in your Assignment 5 program (except for that program's main function.

    • A boolean function which reads the contents of an input text file into memory and returns true if successful, false in the event of input error. The function should take parameters as follows: (1) the name of the input file (as a string class object), (2) the array of account numbers, (3) the array of account balances, (4) the array of account names, and (5) a reference parameter for the number of elements that the function has actually input into each of the three arrays.

    • A void function which outputs the contents of the three arrays into an output text file. This function should take parameters as follows: (1) the name of the input file (as a string class object), (2) the array of account numbers, (3) the array of account balances, (4) the array of account names, and (5) the length of the meaningfully defined portion of each of the three arrays.

    • A function which asks the user for an account number and, once a valid account number is obtained from the user, returns the index of that account number in the array of account numbers. This function should take as parameters (1) the array of account numbers and (2) the length of the meaningfully defined portion of the array.

      This function should prompt the user to enter an account number. If the account number is invalid, an error message is printed and the user is prompted again for the account number. This occurs repeatedly, if necessary, until the user enters a valid account number. (Of course, if a valid account number is entered the first time, the user is not prompted for it again. Also, if the user enters a non-numeric character, the program should print an error message and then quit rather than prompt again for input.) Hint: To determine whether the entered number is valid, your program should search the array of account numbers.

      To make the program quit (rather than just make the function quit), use the following line of code:

         exit(1);
      

      To call the exit function, you will need to include the standard library header file <cstdlib> as follows:

         #include <cstdlib>
      

      Note that this function will need to use cin and cout as global variables. It should be commented accordingly.

    All functions should be accompanied by comments as specified in the Assignment 5 tutorial on Tutorial on programmer-defined functions. All primitive data type parameters should be passed by value when it is not necessary to pass them by reference. On the other hand, all object parameters (e.g. string class objects such as the filenames) should be passed by reference, not by value. In cases where an object or array is not changed by a function, the object or array parameter should be declared const.

    Do not use any global variables except for cin and cout (which you do not need to declare, because they are declared for you in header file <iostream>). But do feel free to use any global constants (declared using the const keyword) that you may deem appropriate, if any. It is recommended that the size of the three arrays be declared as a global constant.


  5. Preparing to hand in your homework

    Run the script file hw06.sh to make sure your programs work correctly and that they have the correct filenames. The script file hw06.sh can be copied into your present working directory as follows:

       cp ~nixon/cs111/hw06/hw06.sh .
    

    Then, create a tar file as you did for earlier assignments. The tar file must have a filename in exactly the following format:

       lastname_accountname_6.tar
    

    replacing lastname with your actual last name (spelled as the Registrar's Office spells it, as on your tuition bill or bursar's recepet) in lower-case letters only (not capital letters), and replacing accountname with your actual forbin account name. The "6" indicates Assignment 6.

    The tar file must contain the following source code file, and only this file:

    1. atm2.cpp

    The tar file must be submitted to your instructor at the appropriate E-mail address, as listed on the instructor E-mail address page.

    Be sure to hand in a printout, as usual.


Back to: