CS140 -- Midterm Exam: Answers


Questions 1-3

The output of this code is: (try it out -- in q1-3.c)
UNIX> q1-3
2 10
12 0xa
2 10
UNIX>
Therefore the answers are: Many of you said that the last line was "12 6". This would only happen if i and j in main() were modified by the call to a(). However, in C, variables are passed by value, which means that i and j in the procedure a() are copies of main()'s i and j. This means that the "j -= 4" line doesn't do anything. True. I was just testing to see if you knew this basic truth about parameter passing in C.

Question 4

This one simply reverses s1 and prints it out: (try it out -- in q4.c)
UNIX> q4
!xiS miH eviG
UNIX>
Therefore, the answer is b.

Questions 5-6

Revstring reverses the input string, and then returns a pointer to it. Therefore, after the line ``s = revstring(s1),'' both s and s1 point to the same piece of memory, which is the string ``!xiS miH eviG.'' After the strcpy(), this piece of memory becomes ``Jim'', and then after the call to revstring it becomes ``miJ''. Therefore, both s1 and s point to the string ``miJ''. Thus, the output to the program is: (try it out -- in q5.c)
UNIX> q5
miJ
miJ
UNIX>
So the answer to question 5 is d, and the answer to question 6 is d.

Question 7

No memory is ever allocated for s. Therefore, the strcpy() statement is going to try to copy the string ``Jim'' into an unknown memory location. This means anything could happen -- segmentation violation (which is the most likely), bus error, or something else. Therefore, the answer is h, although j is almost as good of an answer. When I tried it out, I got differing results on different machines. On cetus1a, it printed out ``Jim'' as if there were actually memory allocated for s. On cobra (a Free-BSD-based pentium), I got a bus error.

Question 8

This program adds each word of standard input weighed by which word number it is on that line. So, on the first line of this input, total is 1*1 + 2*2 + 3*3 = 14. On the second line, total is increased by 1*4 + 2+5. Therefore, total is 14+14 = 28. The answer is g.
UNIX> q8-11
1 2 3
  4 5
< CNTL-D >
28
UNIX>

Question 9

When the program hits the word ``Jim,'' the sscanf() statement will return 0. Therefore, it will print ``Line 2 field 1'' and exit:
UNIX> q8-11
1 2 3
0 Jim Plank
Line 2 field 1
UNIX>
The answer is l.

Question 10

There's nothing special about the '#' character -- this is the fields library, not token.c. Therefore, it will print ``Line 2 field 0'' when it hits the '#' character, and exit:
UNIX> q8-11
1 2 3
# 0 Jim Plank
Line 2 field 0
UNIX> 
The answer is k.

Question 11

The blank line does nothing here -- the for() statement is skipped since is->NF == 0, and the next line of input is processed. Therefore, total is 1*1 + 2*2 + 3*3 + 1*4 + 1*0 + 2*2 = 22. The answer is e.
UNIX> q8-11
1 2 3

4
0 2
< CNTL-D >
22
UNIX> 

Question 12

There is only one right answer here: b. Answers a, d and e return pointers to memory that goes away when make_new_person() exits, and therefore are incorrect. Answer c will not compile -- you cannot use an ampersand in the left-hand side of a C expression.

Question 13

There are two right answers here: c and e, which both do the same thing, although c is the better way since it is easier to read. Answers a and d both will not compile. Answer b is wrong because you need to allocate storage for a copy of the names. Otherwise, the firstname field for each Person will point to the same string (same with the lastname field). Finally, both f and g need to allocate storage in order to perform the strcpy(). Thier problem is just like in Question 7.

Question 14

There are two right answers here: c and g. Answers a and b set the age to a pointer -- they will give compiler warnings and the age will be garbage. Answer d is half right -- the age will be fine, but you do not need to call strdup() and doing so will give your program a memory leak. Answer e won't compile, and answer f will probably dump core, since you need to pass it the address of p->age. Finally, answer h will probably compile and run, but like answers a and b, they set p->age to be a pointer and not an integer.

Question 15

This is very straightforward: (In q15.c):
main(int argc, char **argv)
{
  int i;
  int l;

  for (i = 1; i < argc; i++) {
    l = strlen(argv[i]);   
    printf("%c\n", argv[i][l-1]);
  }
}

Question 16

You need to allocate an array of n (char *)'s. Then read in the first n lines of standard input, and strdup() them into the array. If standard input has fewer than n lines, you adjust n to be the number of lines in standard input. Then you traverse thea array backwards, calling fprintf() to put the lines into the output file.

There are three places you need to error check: the number of arguments, n (it should be a number greater than zero), and whether you can open the file for writing. Note, in my solution, I used atoi() and then tested to see if n was less than or equal to zero. If the first argument is not a number, atoi() returns zero, so that error condition is caught. If you use sscanf() you'll have to test the return value to see if the argument was a number. Alternatively, you can set n to zero before the sscanf(), and then if the argument is not a number, n's value will be unchanged, and the error will be flagged without testing the return value.

You also can use gets() to read standard input, rather than the fields library.

Here is a correct answer. (In q16.c):

#include < stdio.h >
#include < string.h >
#include "fields.h"

main(int argc, char **argv)
{
    /* Make variable declarations */

    FILE *f;       /* For reading in the file */
    int n;         /* Number of lines */
    char **array;  /* Array for holding n lines */
    IS is;         /* Inputstruct for reading input */
    int i;         /* Induction variable for the for loops */

    /* Make sure you have the right number of command line arguments */

    if (argc != 3) {
      fprintf(stderr, "usage: revn n filename\n");
      exit(1);
    }

    /* Make sure n is a legal value */

    n = atoi(argv[1]);  /* You could also do a sscanf here */
    if (n <= 0) {
      fprintf(stderr, "Bad value of n\n");
      exit(1);
    }

   /* Open the file, allocate your array to hold the lines */

    f = fopen(argv[2], "w");
    if (f == NULL) { perror(argv[2]); exit(1); }
    array = (char **) malloc(sizeof(char *) * n);
   
   /* Read in the first n lines (or the entire file if it has < n lines */
   /* There are other ways to do this, but this is pretty clean */

    is = new_inputstruct(NULL);
    for (i = 0; i < n; i++) {
      if (get_line(is) < 0) {
        n = i;
      } else {
        array[i] = strdup(is->text1);
      }
    }

   /* Print out the first n lines to the file in reverse order */

   for (i = n-1; i >= 0; i--) {
     fprintf(f, "%s", array[i]);
   }

}