CS 1713 Section 3
Spring 1997
Exam 1

Write your name and answer the following problems on the paper provided. You may keep this question paper. This exam is worth 100 points. Keep your answers concise. Points will be taken off for handwriting that is hard to read; take an extra sheet of paper if you need it, rather than erasing an entire answer and starting over on the same sheet.

1. True/False (30 points). Answer True or False for each of the following. For the arithmetic expressions, write True if the expression evaluates to True in C, i.e., non-zero; False otherwise.

  1. A single binary digit is referred to as a byte.
    False (it's a "bit," not "byte.")
  2. If you read past the end of the file, fscanf() automatically begins reading from the beginning again.
    False
  3. The C compiler is an example of a hardware component.
    False
  4. The Fast Fourier Transform takes an array of complex numbers from the frequency domain to the time domain.
    False (it's the other way around)
  5. A Finite State Automaton actually has an infinite number of states.
    False (that's what "finite" means)
  6. The %lf token must be used with printf() for float values.
    False
  7. C is a case-insensitive language.
    False
  8. Arrays declared to be of size 100 actually contain 101 elements.
    False
  9. (21 % 4 == 25 % 4)
    True
  10. (2 == 3) || (4 == 4)
    True
  11. 1 && ((2 == 3) || (2 == 4) || (2 == 2))
    True
  12. 'a' < 'b'
    True ('a' comes before 'b' in alphabetic order, as well as in ASCII)
  13. A character is represented inside the computer as an ASCII value.
    True
  14. The ls command is an example of software.
    True
  15. Access to an array is faster than access to a file.
    True (about a million times faster, since arrays are memory and files are hard disk)
II. Short Answer (20 points). Answer the following in one or two sentences each.
  1. How are strings represented in C?
    Null-terminated arrays of characters
    
  2. What does ``call by value'' mean?
    A function receives the value of a parameter, not the location.  If the
    parameter is changed, the original argument remains the same.
    
  3. I have just written a C program called foo.c that uses sqrt(). I have included math.h in the program, but I am getting this error message:
    Undefined                       first referenced
     symbol                             in file
    sqrt                                foo.o
    ld: fatal: Symbol referencing errors. No output written to foo
    
    What should I do to correct the error?
    You forgot to link in the math library.  Do: "cc -o foo foo.c -lm"
    
  4. Why should there be two different floating point types, float and double? What is the advantage and disadvantage of each?
    double has twice the precision of float, but at twice the memory consumption,
    i.e., it uses more memory.
    float has half the precision of double, but uses less memory.
    
  5. In class, we saw an example of an abstract data type, using arrays and a set of support functions to implement arrays of complex numbers. What is the advantage of this approach over not using the support functions, i.e. just doing it with statements like array[i*2+1] = val; etc.?
    There are a couple of advantages.  It makes it easier to read, since the
    functions have meaningful identifier names.  "set_real_part (foo, i, 10.0)"
    means more to the reader than "foo[i*2] = 10.0".  Also, you can change
    the implementation of the abstract data type without changing the code that
    uses it.  
    
III. Program Analysis (20 points). Consider the following C program. It is supposed to read in a list of numbers from a file named on the command line and print their average. Find and describe four errors in the program, classifying them as either syntactic or semantic, and either run-time or compile-time.
#include <stdio.h>

int main (int argc, char *argv[]) {
	FILE	f;
	float	num, avg, sum;

	f = fopen (argv[1]);
	n = 0;
	while (!feof (f))
		scanf ('%f', num);
		sum = sum + num;
		n++;
	}
	avg = sum / n;
	printf ("the average is %lf\n", avg);
	exit (0);
}
There are many errors.  
1. The line with "while" is missing a { .  Syntax error.
2. n is not declared.  Semantic error.
3. f is not declared as a FILE pointer. Either syntax or semantic is acceptable.
4. The scanf format string should be in double quotes, i.e., "%f".  Either
syntax or semantic is acceptable.
5. sum is not initialized.  Semantic error.
6. The last thing scanf reads will be the end of file, not a number.  This will
bias the average.  Semantic error.
7. fopen is called with only one parameter.  Either syntax or semantic is acceptable.
8. argc could possibly not be 2, but no check is made.  Semantic error.
9. The file may not exist or be readable, but no check is made.  Semantic error.
10.  The file could be empty in which case n will be zero, causing a division
by zero.  Semantic error.
11. The "%lf" token is used with a float.  Semantic error.
IV. Programming Problems (30 points).
  1. Write a C function that accepts as a parameter an array v of floats and an integer n, and returns the maximum among the 0..n-1 elements in the array. in the array. The first line of your function should look like this:
    float max (float v[], int n) {
    
    float max (float v[], int n) {
    	float	m;
    	int	i;
    
    	m = v[0];
    	for (i=1; i<n; i++) 
    		if (v[i] > m) m = v[i];
    	return m;
    }
    
  2. Write a C void function that accepts as a parameter an integer key, with a value from 1 through 88, and prints the note symbol associated with that piano key. Recall that the notes of the piano, starting with key #1, are A, A#, B, C, C#, D, D#, E, F, F#, G, and G#, and repeat every twelfth key. The first line of your function should look like this:
    void print_note (int key) {
    
    void print_note (int key) {
    	switch ( (key-1) % 12) {
    		case 0: printf ("A"); break;
    		case 1: printf ("A#"); break;
    		case 2: printf ("B"); break;
    		case 3: printf ("C"); break;
    		case 4: printf ("C#"); break;
    		case 5: printf ("D"); break;
    		case 6: printf ("D#"); break;
    		case 7: printf ("E"); break;
    		case 8: printf ("F"); break;
    		case 9: printf ("F#"); break;
    		case 10: printf ("G"); break;
    		case 11: printf ("G#"); break;
    	}
    }
    
    You could also have used twelve "if" statements instead of "switch/case".
    
  3. An integer is square-free if it is not a multiple of a perfect square. For example, 35 is square-free; it is 5 times 7. 100 is not square-free; it is a multiple of 25, a square. Any square is also trivially not square-free. Clearly, if there is no positive integer i less than n such that i*i divides n evenly, then n is square-free. Write a C program that prints the square-free numbers from 1 through 1000.
    #include <stdio.h>
    
    int main () {
    	int	i, j, k;
    
    	for (i=1; i<=1000; i++) {
    		k = 1;
    		for (j=2; j<i; j++)
    			if (i % (j*j) == 0) k = 0;
    		if (k) printf ("%d\n", i);
    	}
    }