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:
- Question 1: c
- Question 2: i
- Question 3: c
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]);
}
}