CS360 Midterm Exam #2. March 11, 2014. James S. Plank
Answers and Grading
Question 1: 16 Points
Here we go again. In the first three statements we set:
- s is 0x572b20.
- s[0] is 0x572b54. As a string, that is "X+W".
- s[4] is 0x572b44. As a string, that is "H+W".
- p and therefore ip are both 0x572b28. So, *ip is 5712716
and ip[1] is 5712696.
Next, we set x to 0x572b20. s[1] is 0x572b30, so the for loop sets
the four bytes starting at 0x572b30 to 'T' '0' 'L' '8'.
The '8' overwrites the null character, so s[1] becomes seven digits long.
That means that the string s[1]
is "TOL8<+W".
Finally, the hex. 0x7c54 = 0111 1100 0101 0100. The right shift turns that into:
0111 1100 0101 01, and when we regroup that by fours, that becomes
0001 1111 0001 0101. The answer is 0x1f15.
0xa45e = 1010 0100 0101 1110. The left shift turns that into:
1010 0100 0101 1110 00, and when we regroup by fours, that becomes
10 1001 0001 0111 1000. The answer is 0x29178.
Final output:
1. 0x572b20
2. X+W
3. H+W
4. 5712716
5. 5712696
6. T0L8<+W
7. 0x1f15
8. 0x29178
|
Grading
Two points per part.
For line 5, you got full credit if the integer you printed was the one directly after the
one that you printed in line 4.
For line 8, you got 1.8 points if you left off the initial "2".
Question 2: 15 Points
- A. &p is fp: 0xffff440
- B. &x is fp-4: 0xffff43c
- C. &(b[0]) is fp-12: 0xffff434
- D. &i is fp+12: 0xffff44c
- E. i is [fp+12]: 0xffff450
- F. Push 16. I'm hoping the class gets 100% on that one!
- G. That's [fp+4]: 0xffff460
- H. Four bytes past the jsr call is [fp+8] = 0x10448, so the answer is 0x10444.
- I. &i is fp+16: 0xffff450
- J. [fp] = 0x10400
- K. The address of s[0] is [fp+16]: 0xffff45c
- L. The address of s[1] is [fp+16]+1: 0xffff45d
- M. x is 0xffff44c, so *x is 0xffff450.
- N. That will be fp-16: 0xffff430.
- O. The address of b[3] is (fp-12)+12 = fp. So the value is 0x10400.
Grading
1 point per answer. I wrote a program to grade this so that y'all could get optimal
partial credit. First, there were two typos on the exam:
- 1 - I had the top memory address as 0xffff428 rather than 0xffff42c. To handle that, I
assumed that 0xffff42c has the same value as 0xffff428, and when you gave me an address of
428 or 424, I added four. That solved most problems there.
- 2 - I had the 0 and 1 mixed up in the parens. For that reason, if you gave them in either
order, you got full credit.
Here's the partial credit rubric:
- A: If you gave any legal address but the correct one, you got 0.5
- B: If you gave the correct answer, or you gave an address four lower than part A, you
got full credit. Otherwise, you got half for a legal address.
- C: If you gave the correct answer, or you gave an address eight lower than part B, you
got full credit. Otherwise, you got 0.3 for a legal address.
- D: You had to get this one right for full credit. No partial credit.
- E: You got full credit if you gave the contents of the address that you gave in part D.
- F: Full credit for 16. Half for 12 or 20.
- G: You had to get this one right for full credit. No partial credit.
- H: Half credit for 0x10448 or 0x10448.
0.3 for any multiple of 4 less than 0x1044c or greater than 0x10400.
- I: Full credit if your answer is four greater than your answer for D.
0.3 if your answer is four less than your answer for D.
- J: You got full credit if you gave the contents of the address that you gave in part A.
- K: You got full credit if you gave the contents of the address that you gave in part I,
or one plus that. Half credit if it is four plus that.
- L: Full credit if the difference between this answer and the one for part K is one.
Half credit if that difference is four.
- M: Full credit you treat your answer for B as a pointer, and then do double indirection.
Half credit if you do single indirection.
- N: Full credit if you subtracted your answer to F from 0xffff440 (fp). Half credit if you
were off by four from this value.
- O: Full credit if you added twelve to the memory pointed to by your answer to C.
Half credit if your answer was off by four, or if you added 12 to your answer to C.
Question 3: 16 Points
This is a nuts and bolts opendir/readdir/stat/jrb program:
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include "jrb.h"
main()
{
DIR *d;
struct dirent *de;
struct stat buf;
JRB t, tmp;
d = opendir(".");
if (d == NULL) { perror("."); exit(1); }
t = make_jrb();
for (de = readdir(d); de != NULL; de = readdir(d)) {
if (stat(de->d_name, &buf) != 0) {
perror(de->d_name);
exit(1);
}
if (jrb_find_int(t, buf.st_ino) == NULL) {
jrb_insert_int(t, buf.st_ino, new_jval_s(strdup(de->d_name)));
}
}
jrb_traverse(tmp, t) printf("%s\n", tmp->val.s);
}
|
Grading: 16 points
8 points for reading the files and printing them, another 8 for
calling stat and using the red-black tree on inodes.
Question 4: 16 Points
You had to spend time reading the code, but I was hoping that it was
pretty clear that R16_read() reads 16 bytes from fd
into buf, but it does it by using a 4K buffer. That way, it's
only doing one read() call every 4096 bytes.
The mechanics of eof and p are not too subtle.
If we've reached EOF, then eof is the index one past
the end of the file. If we haven't readched EOF, then eof
is -1.
On the other hand, p is the pointer in the buffer to where we
need to read next. When it equals 4096, we have to make a read()
call to fill the buffer.
Part A:
We need to set up the buffer, and then successively call R16_read()
until it returns an empty string:
#include <stdio.h>
#include <stdlib.h>
#include "r16.h"
main()
{
char buf[17];
void *r16;
r16 = R16_setup(0);
while (1) {
R16_read(r16, buf);
if (buf[0] == '\0') exit(0);
printf("%s", buf);
}
}
|
Part B: Slower because we are making 4096/64 = 64 times as many
read() calls.
Part C: Slower, but not by much. Fread() buffers, so it's
going to make the same number of read() calls. However,
the following three factors will make it slower:
- Since we call it with 15,
it will have to make more fread() calls than the Part A program
made R16_read() calls.
- There are fewer parameters to process on the
R16_read() calls than the fread() calls.
- The R16_Read() calls work in units of 16, so it never has
to worry about calls that read from the end of the buffer, then require
a read() call, and then from the beginning of the buffer.
Since 15 does not divide 4096, the fread() version has to both
check for this, and then do it every now and then.
Part D:
If my input file contains the byte 0, then the printf() statement
will stop printing when it sees the 0, because that's the null character.
Part E:
The read() call will fail and return -1. Therefore, it will act
as though the buffer is full, and it will fill in buf with the
first 16 random bytes of r->b.
Grading
- Part A: 6 points, which no one got, because everyone tried to access either eof
or p from the struct. You can't do that, because the header file only gives you a (void *).
- Part B: 3 points
- Part C: 3 points. You had to get two of the three reasons for full credit.
- Part D: 2 points.
- Part E: 2 points.