CPSC 124, Winter 1998

First Test


This is the first test given in CPSC 124: Introductory Programming, Winter 1998. See the information page for that course for more information.

The answers given here are sample answers that would receive full credit. However, they are not necessarily the only correct answers. In some cases, I give more detailed answers here than would be necessary to get full credit.


Question 1: Explain the terms machine language, high-level language, compiler, and interpreter, and explain the relationships among these terms.

Answer: A computer can only directly execute a program that is written in machine language. Machine language consists of instructions coded as binary numbers that are executed directly by the CPU. Each type of CPU has its own machine language. But programs are usually written in high-level languages, which are closer to human languages and easier for people to work with. High-level language programs must be translated into machine language because they can be executed by a computer. The translation can be done either by a compiler, which translates a program all at once into an equivalent program in another language, or by an interpreter, which translates and executes instructions one-by-one. The Java compiler translates programs written in the high-level language Java into the Java bytecode language. Java bytecode programs are then executed by an interpreter.


Question 2: Explain the terms syntax and semantics. As an example, discuss both the syntax and the semantics of the assignment statement in Java.

Answer: Syntax refers to the structure or grammar of a language. Syntax determines what makes a legal program -- one that can be compiled and executed. The syntax of an assignment statement says that it must consist of a variable, followed by an "=", followed by an expression, followed by a semicolon. Semantics refers to meaning. Semantics determines what is actually done when a program is executed. The semantics of an assignment statement is that when it is executed, the expression on the right-hand side of the "=" is evaluated and the value is stored in the variable on the left-hand side.


Question 3: Discuss the concept of parameters. What are parameters for? In Java, there are dummy parameters and actual parameters. Why do these two types of parameters exist? Where is each kind of parameter found?

Answer: Parameters are used for communication between a subroutine and the part of the program that calls the subroutine. If a subroutine is thought of as a black box, then parameters are part of the interface to that black box. Dummy parameters are found in the subroutine definition. Actual parameters are found in subroutine call statements. In the definition of a subroutine, a dummy parameter represents an actual value that will be passed to the subroutine when the subroutine is called. The actual value is not known at the time the subroutine is written, and in fact the subroutine has to work no matter what actual value is provided to the subroutine.


Question 4: Write a for statement that will print out the numbers 3, 6, 9, 12, 15, 18, 21, 24, 27, and 30.

Answer: Here is one of many possible answers:

            for (int number = 3; number <= 30; number = number + 3) {
                
                System.out.println(number);
                
            }

Question 5: Suppose that g is an object of type Graphics. Recall that g.drawRect(x,y,w,h) will draw a rectangle with its upper left corner at the point (x,y). The width of the rectangle is w and the height is h. Write a loop that will draw 10 small squares in a line, like this:

line of 10 squares

Use the g.drawRect method to draw the squares. Assume that the first square has its upper left corner at (0,0). Each square is 15 pixels by 15 pixels, and there are 15 pixels between the squares. You can use a for loop or a while loop.

Answer:Here are three possible answers, two using for loops and one using a while loop.

         1)  The first version counts off ten squares.  The variable x
             keeps track of the left edge of the square.  After each square
             is drawn, x is incremented by 30.  (That's allowing 15 pixels 
             for the square and 15 pixels between the squares.)
             
                int x = 0;
                for (int count = 0; count < 10; count++) {
                   g.drawRect(x,0,15,15);
                   x = x + 30;
                }
                
                
         2)  In the second version, x is used as the for loop
             variable.  Since there are 10 squares, we can calculate that
             the last value of x is 270.
             
                for (int x = 0; x <= 270; x = x + 30) {
                   g.drawRect(x,0,15,15);
                }
                   
                   
         3)  The third version is similar to the second, except that
             a while loop is used.
             
                int x = 0;
                while (x < 300) {
                   g.drawRect(x,0,15,15);
                   x = x + 30;
                }

Question 6: Suppose that the price of admission to a museum depends on the customer's age. Children 12 years old or younger pay $2.00. Senior citizens aged 62 or over pay $3.00. General admission for everyone else is $5.00. Write a program segment that will ask the user to enter his or her age, and then print a message stating the user's price of admission. Use an if statement. You don't have to write a complete program, but you should declare any variables that you use.

Answer: I use TextIO.put() in my answer, but you could use System.out.print() instead.

              int age; // the customer's age
              
              TextIO.put("What is your age? ");
              age = TextIO.getlnInt();
              
              if (age <= 12) {
                 TextIO.putln("Your admission price is $2.00");
              }
              else if (age >= 62) {
                 TextIO.putln("Your admission price is $3.00");
              }
              else {
                 TextIO.putln("Your admission price is $5.00");
              }

Question 7: Write a complete subroutine, "static double doOperation(char operator, double x, double y)". When it is called, the subroutine will compute the value of one of the expressions x + y, x - y, x * y, or x / y. The value of the parameter operator tells the subroutine which value to compute. The answer should be returned as the value of the subroutine. You can use either an if statement or a switch statement in your subroutine.

Answer: The question doesn't say what value the function should return if the parameter operator does not have one of the values '+', '-', '*', or '/'. You could say that the contract of the subroutine requires that operator have one of these values, so it doesn't matter what answer is returned in that case. However, the subroutine has to return some value, so I will return a value of 0.0 in case operator does not have one of the expected values.

   1) Using a switch statement:

         static double doOperation(char operator, double x, double y) {
            double answer;
            switch (operator) {
               case '+':
                  answer = x + y;
                  break;
               case '-':
                  answer = x - y;
                  break;
               case '*':
                  answer = x * y;
                  break;
               case '/':
                  answer = x / y;
                  break;
               default:
                  answer = 0.0;
            }
            return answer;
         }
         

   2) Using an if statement:

         static double doOperation(char operator, double x, double y) {
            double answer;
            if (operator == '+')
               answer = x + y;
            else if (operator == '+')
               answer = x - y;
            else if (operator == '+')
               answer = x * y;
            else if (operator == '+')
               answer = x / y;
            else
               answer = 0.0;
            return answer;
         }
         
         
   3) Using a switch statement, with "return" instead of "break":

         static double doOperation(char operator, double x, double y) {
            switch (operator) {
               case '+':
                  return x + y;
               case '-':
                  return x - y;
               case '*':
                  return x * y;
               case '/':
                  return x / y;
               default:
                  return 0.0;
            }
         }

Question 8: Show the exact output that would be produce when the following program is executed. (If you explain your reasoning, you might get more partial credit for an incorrect answer.)

              public class TestQuestion {
                 public static void main(String[] args) {
                    int x, y;
                    x = 1;
                    y = 1;
                    while (y < 16) {
                       y = 2*y;
                       x = x + y;
                       System.out.println("x = " + x + " and y = " y);
                    } // end while
                 } // end main
              } // end class TestQuestion

Answer: The table on the left shows the values that the variables y and x take on as the program is executed. The output from the program is shown on the right.

       y   |   x         OUTPUT:
    -------|-------      -------------------------------
       1   |   1
       2   |   3             x = 3 and y = 2
       4   |   7             x = 7 and y = 4
       8   |  15             x = 15 and y = 8
      16   |  31             x = 31 and y = 16

Question 9: Fill in the following subroutine so that it counts the number of times that the character ch occurs in the string str. That is, you want to count the number of values of i such that str.charAt(i) == ch. The answer should be returned as the value of the subroutine.

        public static int countCharInString(String str, char ch) {
          .
          .
          .
        }

Answer:

        public static int countCharInString(String str, char ch) {
           int count = 0;
           for (int i = 0; i < str.length(); i++) {
              if (str.charAt(i) == ch)
                 count++;
           }
           return count;
        }

Question 10: Explain what is meant by a named constant in a Java program. What is the main reason for using a named constant instead of a literal value in a program?

Answer: A named constant is a variable that has been declared to be ``final.'' This means that the value of the variable can't be changed while the program is running. One reason to used named constants is to make the program more readable, since a name such as MONTH_IN_YEAR will mean more to the reader than a literal number such as 12. However, the main reason for using named constants is that if it becomes necessary to change the value of the constant, the change can be made on one line of the program, instead of searching for a literal value and changing it each time it occurs in the program.

As an example, a named constant could be declared to represent the interest rate:

        static final INTEREST_RATE = 0.075;

If the interest must be changed to 0.078, you can just change this line to

        static final INTEREST_RATE = 0.078;

and recompile the program.


Question 11: There are two approaches to designing a program to perform a given task: top-down design and bottom-up design. Discuss these two approaches and discuss how subroutines fit into the process.

Answer: Top-down design refers to breaking a problem down into subproblems, which can then be further broken down if necessary until eventually you come to problems that you know how to solve. Step-wise refinement, using pseudocode, is one way of going about top-down design. In step-wise refinement, you start with a general outline of an algorithm. This outline is refined in a series of stages, where each stage adds more detail. This continues until you have a complete algorithm in which each step can be translated into programming language.

Subroutines fit into this process in two ways. First, when you divide a problem into subproblems, you can write a subroutine to solve each problem. Second, if you come to some subproblem, and you already have a subroutine to solve that problem, you don't have to solve it again. You can just use the subroutine that you already have.


David Eck, 7 October 1998