void memcpy(void *dest, const void *src, int bytes); |
Here's a procedure:
void a(unsigned int *x) { unsigned char *c; unsigned int y, z; c = (unsigned char *) x; y = 0; z = 0; memcpy(&y, c+2, sizeof(unsigned int)); memcpy(&z, x+3, 3); printf("1 0x%02x\n", c[0]); printf("2 0x%02x\n", c[5]); printf("3 0x%02x\n", c[10]); printf("4 0x%02x\n", c[15]); printf("5 0x%08x\n", (unsigned int) (x+1)); printf("6 0x%08x\n", x[1]); printf("7 0x%08x\n", y); printf("8 0x%08x\n", z); } |
When we run it, x is 0x04e05030, and here are the values of the 16 bytes of memory starting with x:
Address Value 0x04e05030 0x893b6165 0x04e05034 0x50f6dc88 0x04e05038 0x04e05034 0x04e0503c 0xd4cfa7ce |
Please answer with the 8 lines of output of this procedure. Please don't put anything extraneous into your answer box.
Address Value +3 +2 +1 +0 0x04e05030 89 3b 61 65 0x04e05034 50 f6 dc 88 0x04e05038 04 e0 50 34 0x04e0503c d4 cf a7 ce |
1 0x65 # Little endian means that its the last two digits on the 0x04e5030 line. 2 0xdc # This is the +1 byte for pointer 0x04e05034 3 0xe0 # This is the +2 byte for pointer 0x04e05038 4 0xd4 # This is the +3 byte for pointer 0x04e0503c 5 0x04e05034 # Adding 1 to x adds 4 to the pointer. 6 0x50f6dc88 # The four bytes starting at 0x04e05034, printed as an integer. 7 0xdc88893b # y is 3b 89 88 dc, but in little endian: 0xdc88893b 8 0x00cfa7ce # z is ce a7 cf 00, but in little endian: 0x00cfa7ceGrading: 2 points per question. There's some partial credit.
char *strcpy(char *dest, const char *source); char *strcat(char *dest, const char *source); |
Here is a procedure:
void a(char *b, char *c, char *d) { strcpy(b+2, c); strcpy(b+12, c); strcat(b, d); b[2] = '\0'; printf("1 %s\n", b); printf("2 %s\n", b+5); printf("3 %s\n", b+10); printf("4 %s\n", b+15); printf("5 %s\n", b+20); } |
Please put what the output to a() is when you run it with the following arguments. I've put the numbers in to help you count:
0123456789012345678901 b = "TennesseeVolunteersWin" c = "Fred" d = "123" |
01234567890123456789012 b = TennesseeVolunteersWin* ^ ^ | | b+2 b+12 |
The first strcpy copies "Fred" to b+2:
01234567890123456789012 b = TeFred*eeVolunteersWin* ^ ^ | | b+2 b+12 |
The second strcpy() copies "Fred" to b+12:
01234567890123456789012 b = TeFred*eeVolFred*rsWin* ^ ^ | | b+2 b+12 |
The strcat() finds the null character, which is at (b+6). It puts "123" there:
01234567890123456789012 b = TeFred123*olFred*rsWin* ^ ^ | | b+2 b+12 |
Finally, we set b[2] to the null character:
01234567890123456789012 b = Te*red123*olFred*rsWin* ^ ^ | | b+2 b+12 |
So:
1 Te 2 d123 3 olFred 4 d 5 inGrading: 2 points per question. There's some partial credit.
You are on a little-endian machine with 8-byte pointers. You are running the following procedure:
typedef struct { unsigned long dv; unsigned long *dp; } DS; void a(unsigned long *p) { unsigned int *ip; unsigned long **r; DS *d; unsigned long x; ip = (unsigned int *) p; r = (unsigned long **) p; d = (DS *) p; x = (unsigned long) (p+4); printf("1 0x%02lx\n", p[4] & 0xff); printf("2 0x%02lx\n", r[1][0] & 0xff); printf("3 0x%02lx\n", r[0][2] & 0xff); printf("4 0x%02lx\n", d->dv & 0xff); printf("5 0x%02lx\n", *(d->dp) & 0xff); printf("6 0x%02lx\n", (x+1) & 0xff); printf("7 0x%02x\n", ip[2] & 0xff); printf("8 0x%02x\n", ip[11] & 0xff); } |
You run a() with p = 0x00002e1529b17620. Here's the state of memory starting at that address:
Address Value 7 6 5 4 3 2 1 0 0x00002e1529b17620 0x00002e1529b17640 0x00002e1529b17628 0x00002e1529b17648 0x00002e1529b17630 0x00002e1529b17638 0x00002e1529b17638 0x00002e1529b17630 0x00002e1529b17640 0x00002e1529b17650 0x00002e1529b17648 0x00002e1529b17620 0x00002e1529b17650 0x00002e1529b17658 0x00002e1529b17658 0x00002e1529b17628 |
Please enter the output of a().
1 0x50 # p[4] is 0x00002e1529b17650, so this is byte 0 of that: 0x50 2 0x20 # r[1] is 0x00002e1529b17648. r[1][0] is 0x00002e1529b17620: 0x20 3 0x58 # r[0] is 0x00002e1529b17640. r[0][2] is at address 0x00002e1529b17650: 0x00002e1529b17658: 0x58 4 0x40 # d = &(d->dv) = 0x00002e1529b17620, so d->v is 0x00002e1529b17640: 0x40 5 0x20 # &(d->dp) = 0x00002e1529b17628, so d->dp = 0x00002e1529b17648. *(d->dp) = 0x00002e1529b17620: 0x20 6 0x41 # x = p+4 = 0x00002e1529b17640. x+1 simply adds one to that: 0x41 7 0x48 # ip = 0x00002e1529b17620, so (ip+2) = 0x00002e1529b17628. ip[2] is the lower 4 bytes, # which are 0x29b17648. (ip[2] & 0xff) will be the lowest byte: 0x48 8 0x15 # ip+11 is 0x00002e1529b17620 + 0x2c = 0x00002e1529b1764c. So this is the # high four bytes of 0x00002e1529b17648, which is 0x00002e15: 0x15.Grading: 1.5 points per question. There's some partial credit.
int main() { unsigned int hash, l; hash = 0; while (fread(&l, sizeof(unsigned int), 1, stdin) == 1) hash = add_to_hash(hash, l); printf("0x%x\n", hash); } |
And here's program 2:
int main() { unsigned int hash, l; hash = 0; while (read(0, &l, sizeof(unsigned int)) == 1) hash = add_to_hash(hash, l); printf("0x%x\n", hash); } |
Let's suppose that standard input is four megabytes. Please tell me which of these programs will run faster, and then explain why. Your explanation should be a paragraph, and you should use numbers to support your reasoning. In particular, it will be a good idea for you to estimate how long each program will take to run.
Grading: 7 points. You didn't have to have correct numbers, but you didn't get full points unless you gave some numbers to back up your explanation.
If you encounter errors, simply exit(1).
Here are helpful prototypes and structs: Obviously, these are the calls that you should make to solve this problem -- please don't get cute and try popen() or system().
int stat(const char *path, struct stat *buf); int lstat(const char *path, struct stat *buf); DIR * opendir(const char *filename); struct dirent * readdir(DIR *dirp); struct direct { /* Useless stuff omitted */ char *d_name; }; struct stat { dev_t st_dev; /* device inode resides on */ ino_t st_ino; /* inode's number */ mode_t st_mode; /* inode protection mode */ nlink_t st_nlink; /* number of hard links to the file */ uid_t st_uid; /* user-id of owner */ gid_t st_gid; /* group-id of owner */ dev_t st_rdev; /* device type, for special file inode */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last data modification */ time_t st_ctime; /* time of last file status change */ off_t st_size; /* file size, in bytes */ u_long st_flags; /* user defined flags for file */ u_long st_gen; /* file generation number */ }; |
#include <sys/stat.h> #include <stdio.h> #include <string.h> #include <dirent.h> #include <stdlib.h> int main() { DIR *d; struct dirent *de;; struct stat buf; char *name; int n; n = 0; d = opendir("."); if (d == NULL) { perror("."); exit(1); } /* Traverse the current directory. */ for (de = readdir(d); de != NULL; de = readdir(d)) { /* Only work on files that are directories, and that aren't . or .. */ if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) { if (stat(de->d_name, &buf) != 0) exit(1); if (S_ISDIR(buf.st_mode)) { /* Create the filename. This can be much more efficient, as in the lecture on the prsize program, but this is an exam, so as long as you don't have a memory leak, you're good. */ name = (char *) malloc(sizeof(char) * (strlen(de->d_name)+20)); sprintf(name, "%s/f1.txt", de->d_name); /* See if the file exists and is at least 100 bytes. */ if (stat(name, &buf) == 0 && buf.st_size >= 100) n++; /* No memory leak. */ free(name); } } } printf("%d\n", n); return 0; } |
void add_to_data(JRB tree, char *name, char *alias); |
The tree is keyed on name. Each node's val is a dllist of aliases (which are strings). add_to_data() should create a node for the given name if it doesn't exist. Then, it should add the alias to the name's dllist.
It will be called as follows from the main():
add_to_data(tree, is->fields[0], is->fields[1]); |
Do not bother with include files. I don't care. However, the rest of your code should be polished. You don't have to error check.
Here is relevant information from dllist.h and jrb.h:
typedef struct dllist { struct dllist *flink; struct dllist *blink; Jval val; } *Dllist; Dllist new_dllist(); void free_dllist(Dllist); void dll_append(Dllist, Jval); void dll_prepend(Dllist, Jval); void dll_insert_b(Dllist, Jval); void dll_insert_a(Dllist, Jval); void dll_delete_node(Dllist); #define dll_traverse(ptr, list) for (ptr = list->flink; ptr != list; ptr = ptr->flink) typedef struct jrb_node { struct jrb_node *flink; struct jrb_node *blink; Jval key; Jval val; /* Other stuff */ } *JRB; JRB make_jrb(); JRB jrb_insert_str(JRB tree, char *key, Jval val); JRB jrb_find_str(JRB root, char *key); JRB jrb_find_gte_str(JRB root, char *key, int *found); void jrb_delete_node(JRB node); void extern void jrb_free_tree(JRB root); #define jrb_traverse(ptr, lst) for (ptr = list->flink; ptr != list; ptr = ptr->flink) |
void add_to_data(JRB tree, char *name, char *alias) { JRB tmp; Dllist l; tmp = jrb_find_str(tree, name); if (tmp == NULL) { tmp = jrb_insert_str(tree, strdup(name), new_jval_v((void *) new_dllist())); } l = (Dllist) tmp->val.v; dll_append(l, new_jval_v((void *) strdup(alias))); } |
Grading: 5 points.
void print(JRB tree); |
This should print the tree from the previous question. The format should be one line per node of the tree. For each node, print the name, followed by a colon, and then the aliases, each separated by a space.
void print(JRB tree) { JRB tmp; Dllist l, tmpl; jrb_traverse(tmp, tree) { l = (Dllist) tmp->val.v; printf("%s:", tmp->key.s); dll_traverse(tmpl, l) printf(" %s", tmpl->val.v); printf("\n"); } } |
Grading: 5 points.