Midterm - Answers

1. (Multiple choice)

a. The root directory in UNIX   is denoted by \ (tilde).

b. UNIX command that can be used to protect a file from accidental deletion: chmod a-w <filename >.
(There is no save command).

c. The number of different byte values is 256.
(A byte consists of 8 bits. Each bit can have two values: 0,1. Therefore, there are 28=256 different byte values.)

d. A string in C is   an array of char terminating with NULL character , but it can also be treated as   a variable of type char*.

e. A function stub is a temporary replacement of the actual function.

2. Trace the values of variables in the following fragment of code by hand. All variables are int.
10    sum=0; 
11    n=4; 
12    for (j=0; j<n; sum+=n) 
13    { 
14       if (sum>n)
15       { 
16          j= sum && n;
17       }
18       else
19       {
20          n= j || n;
21       }
22    }
line |  sum  |  n   |   j   | cond.(true/false) | comment
----------------------------------------------------------
  10 |  0    |  ?   |   ?   |                   |
----------------------------------------------------------  
  11 |  0    |  4   |   ?   |                   |
----------------------------------------------------------  
  12 |  0    |  4   |   0   | 0<4 true          | enter loop
----------------------------------------------------------  
  14 |  0    |  4   |   0   | 0>4 false         | jump to else
----------------------------------------------------------  
  20 |  0    |  1   |   0   |                   |  0||4 = 1
----------------------------------------------------------  
  22 |  0    |  1   |   0   |                   | repeat loop
----------------------------------------------------------  
12(upd) 1    |  1   |   0   |                   | 0+1=1
----------------------------------------------------------  
12(chk) 1    |  1   |   0   | 0<1 true         | cont.loop
----------------------------------------------------------  
  14 |  1    |  1   |   0   | 1>1 false        |
----------------------------------------------------------  
  20 |  1    |  1   |   0   |                   |  0||1 = 1
----------------------------------------------------------  
  22 |  1    |  1   |   0   |                   | repeat loop
----------------------------------------------------------  
12(upd) 2    |  1   |   0   |                   | 1+1=2
----------------------------------------------------------  
12(chk) 2    |  1   |   0   | 0<1 true         | cont.loop
----------------------------------------------------------  
  14 |  2    |  1   |   0   | 2>1 true         |
----------------------------------------------------------  
  16 |  2    |  1   |   1   |                   | 2&&1 = 1
----------------------------------------------------------  
  22 |  2    |  1   |   1   |                   | repeat loop
----------------------------------------------------------  
12(upd) 3    |  1   |   1   |                   | 2+1=3
----------------------------------------------------------  
12(chk) 3    |  1   |   1   | 1<1 false        | exit loop
----------------------------------------------------------  
(Compile and run this code to compare results.)

3. Determine the output produced by the following piece of code in main (Use a table to trace the values if it helps.) All variables are int. Hint: Numbers 65...90 are the ASCII codes of the letters `A`..`Z` (in the natural order).
10     i=(int)'A';
11     j=(int)'Z';
12     do
13     {
14       if (i%2!=0)
15       {
16          printf("Case 1: i=%d, j=%d\n",i,j);
17          j=f(++i); /* incr.i, then do f(i) */ /* Mistake in test: f(i++) */
18       }
19       else
20       {
21          printf("Case 2: i=%d, j=%d\n",j,i);
22          i=f(j--); /* f(j), then decr.j */ /* Mistake in test: f(--j) */
23       }
24     } while (j>=i);
The function f is defined as follows:
100     int f(int x) 
101     {   
102        x=x-3;
103        printf("%c",x); 
104        return(x);
105     }
While the question asks to determine the output of the program, it's still convinient to use a full-format table to follow all the values.
 line |  i |  j   | x(in f)|   cond.  | output   | comment
----------------------------------------------------------
10-12 | 65 |  90  |        |          |          | enter loop
----------------------------------------------------------  
  14  | 65 |  90  |        | 1!=0  T  |          | 65%2=1
----------------------------------------------------------  
  16 |  65 |  90  |        |          | Case 1: i=65, j=90\n
----------------------------------------------------------  
  17a|  66 |  90  |        |          |          | i++
----------------------------------------------------------  
  17b|  66 |  90  |        |          |          | call f, pass arg. by value
----------------------------------------------------------  
  100|     |      |  66    |          |          | f begins
----------------------------------------------------------  
 102 |     |      |  63    |          |          | 66-3=63
----------------------------------------------------------  
 103 |     |      |  63    |          | symbol with ASCII code 63 (?)
----------------------------------------------------------  
 104 |     |      |  63    |          |          | f returns 63
----------------------------------------------------------  
 17c | 66  | 63   |        |          |          | j=63 received by main
----------------------------------------------------------  
 24  | 66  | 63   |        | 63>=66 F  |         | exit loop
----------------------------------------------------------  
Thus, the output will be:

   Case 1: i=65, j=90
   ?
(Knowledge of a symbol with ASCII code 63 wasn't assumed. The fact that a symbol with ASCII code beyond the range 65..90 is needed is due to a typo in line 102; it had to be "x=x+3". In that case the loop would continue longer and both cases in main would be attended.)
(Compile and run
this code to compare results.)

4. The program presented below is meant to compute the size (number of decimals) of n! for the given integer n>=0. It is based on the following mathematical facts:

a. The number of (decimal) digits in a natural number n is the integral part of   log10n   plus 1. For example, the singlets 1,..,9 satisfy      0<= log10 n   <   1  . Then, for double-digit integers    10 <= n <= 99   we have
              1 <= log10 n < 2,
etc.

b. The values   log10 n!= log10 (1 * 2 * ... * n)   obey the recurrence
              log10 n! =log10 (n-1)! + log10 n,         n >1
with initial value   log10 0!=log10 1=0.

While the approach is smart and allows input values n, for which n! is well beyond the range of C type int, the code was written in a hurry and contains programming errors (however, the library function log10 does indeed exist). Find as many as you can. The programming style is also sloppy. Advise the programmer.
1   Re: your mail */
2
3   main(){
4     int len; /* size of n!, to be found
5     int n  /* given value */    int i; /* iteration index */
6
7    print("Given non-negative n, this program computes size of n!");
8   	    scanf("n=%lf", n);
9   	    if n<=0 {/* stub */}
10    doube logNFac; /* accumulator for log10 (j!), j=0,...,n.
11  		       note: log10 (0!)=0.*/
12
13       /* In loop: log10 (n!) = sum log10(j), j=1,..,n. */
14    do (j==1.0, j<n, n++);
15    (   
16    logNFac+=log10[j]  /* using function log10 from "math.h" */
17    };
18
19    /* Now that log10(n!) is computed, find its integral part */
20    len=(integer) logNFac, /* cast to int */
21
22    /* if the value was rounded up, subtract one */
23    if {Len > lognfac} then
24   --len;
25    /* To obtain size of n!, add 1 to the computed integral part */
26    size=+1;  
27    /* Print result, like this: Size of 4!=2 */
28    printf("Size of %d ! is %f /n, n, len");
29    return.
30  } 
A corrected version is here. Fixed programing errors are shown red, with occasional /* blue comments */. Style enhancements (corrections or comments) are green.
1  /*  Project, Author, Date */

2a #include <stdio.h> /* for printf, scanf */ 
2b #include <math.h> /* for log10 */ 

3a  int main()
3b  {  /* better put the opening brace here */ 
4     int len; /* size of n!, to be found */
5a    int n  /* given value */  ;  
5b    int j; /* iteration index. The original notation `i' was not the one used in the loop. */
10    double logNFac; /* accumulator for log10 (j!), j=0,...,n.  note: log10 (0!)=0.*/ 
11    /*Bring the declaration here. Declarations must precede executable statements*/ 
6
7    printf("Given non-negative n, this program computes size of n!");
8a   printf("\n Please enter n="); /* "n=" wouldn't be printed in scanf */
8b   scanf("%d", &n);
9a   if (n<0) /* n==0 is still OK */ 
9b   {
9c      printf("n should't be negative\n"); /*stub replaced by functional code*/
9d      return (1);   
9e   }
12
13a       /* In loop: log10 (n!) = sum log10(j), j=1,..,n. */
13b   logNFac=0.0;  /* Initialization */
14    for (j=1; j<=n; j++) /* no ; here */;
15    { /* use indentation */  
16    logNFac+=log10((double)j);  /* using function log10 from "math.h" */
17    } /* no ; here */
18
19    /* Now that log10(n!) is computed, find its integral part */
20    len=(int) logNFac; /* cast to int */
21
22    /* if the value was rounded up, subtract one */
23    if (len > logNFac)  /* then */  /* Var.names are case-sensitive */
24       --len;   /* indent */ 
25    /* To obtain size of n!, add 1 to the computed integral part */
26    len+=1;   /*  undef'd varname `size' and wrong shorthand `=+' were here */ 
27    /* Print result, like this: Size of 4 ! is 2 */ 
28    printf("Size of %d ! is %d\n", n, len); 
29    return(0);
30  } 

(Here is a working code.)

5. Write a C program to compute the greatest common divisor (GCD) of the two given positive integers. By definition, GCD(a,b) is the largest integer that divides both a and b. For example, GCD(20,15)=5; GCD(a,1)=1 and GCD(a,a)=a for any a>1.

Mathematical note. The simplest algorithm (inefficient but feasible at modern computers' speed) is to look for common divisors by checking all numbers that do not exceed any of a and b. Since the ancient Greeks didn't have these powerful computers, they came up with a much faster Euclidean Algorithm:
To find the GCD of two unequal numbers, divide the largest by the smaller. Note the remainder and divide the previous divisor by this remainder. Continue the process until a remainder of 0 is obtained. The GCD is the last positive remainder obtained in the process.

Example: Find GCD(168,90).
Step 1:      168/90= 1   rem.78
Step 2:      90/78=1   rem. 12
Step 3:      78/12=6   rem. 6
Step 4:      12   rem. 0
The last positive remainder was 6, therefore GCD(168,90)=6.
Programming note.   Your program should contain all necessary elements (comments, input/output, validation, etc.) You are free to use any of the above two algorithms or a one of your own. Efficiency will matter in the evaluation; however, a priority will be given to correctness, structure, and style of the program.

Here is a possible solution (with Euclidean Algorithm).