<<

CS107 Cynthia Lee Winter 2017 March 2, 2017 CS107 2nd Midterm Examination

This is a closed book, closed note, closed exam. You have 90 minutes to complete all problems. You don’t need to #include any libraries, and you needn’t use assert to guard against any errors. Understand that the majority of points are awarded for concepts taught in CS107, and not prior classes. You don’t get many points for for-loop syntax, but you certainly get points for proper use of &, *, and the low-level functions introduced in the course. DO NOT ADD OR REMOVE PAGES OF THE EXAM (except optionally removing the reference page(s) at the end). If you need extra space for scratch and/or problem responses, use the blank back sides of each page. Changing the pages confuses the online grading system and will cause you to lose points.

We’ll revisit the material from both midterms on the final, with just a very small amount of additional material, so this exam marks a milestone that is very near to the finish line of CS107! Keep pushing, and good luck!

SUNet ID (myth login): @stanford.edu

Name:

I accept the and spirit of the honor . I will neither give nor receive unauthorized aid on this exam.

[signed]

Problem Points Score Grader

1. C generics 11

2. Floats and bitwise ops 12

3. Assembly 11

TOTAL 34

Problem 1: C Generics (11pts) Complete the make_list function. The function takes a pointer to beginning of an array of key- value pairs, the number of elements (number of pairs) in the array, and the size of the value field in . It returns a of the key-value pairs. The keys are strings whose individual chars (including a null terminating ) are stored within the array itself (not char* pointing to memory outside the array), and the values are a generic type of size valuesz bytes. void *make_list(void *arr, size_t nelems, size_t valuesz);

The key string lengths may differ, so the null terminating character marks the end of the string, and (in the following ) the beginning of the value. Following the value’s valuesz bytes is the next key string (again, all contiguous in the input array). The below diagrams show an example input and return value for that input.

arr: nelems: valuesz:

The output linked list should consist of newly allocated void* “blob” nodes that consist of (in this order): a void* next pointer, the key string (stored inside the blob, not as a char* pointing to memory outside the blob), and the value. The nodes should be in the same order as they were in the array, with the end of the list marked by a NULL value in the next pointer of the last node. After you copy the from the array, it is no longer needed and should be freed.

return:

Write your code on the next page. Some code structure is provided to get you started. You should not add code anywhere except where indicated, nor should you modify any of the existing structure.

void *make_list(void *arr, size_t nelems, size_t valuesz) { void *list_front = NULL; void *list_curr = NULL; int blobsize; char *arr_curr = arr; // loop over array for (size_t i = 0; i < nelems; i++) { // set up blob

blobsize = ______; void *node = malloc(blobsize);

memcpy(______, ______,

______);

if (list_front == NULL) { // up first node of list list_front = node; list_curr = node;

______= NULL; } else { // connect list nodes (you add line(s) of code here)

} arr_curr = ______; }

free(______); return list_front; }

Problem 2: Floats and bitwise ops (12 points) Beyoncé and Jay-Z want to set up bank accounts for their twins, and thought maybe would be a fittingly “mini” way to represent the account balance. Help them test the feasibility of using minifloat by saying whether the numbers below can be represented as minifloat or not. For each value:  If the value can be exactly represented as a minifloat, then circle “YES” and write the minifloat representation.  Otherwise circle “NO” and write the nearest representable minifloat (where nearest means smallest difference between the actual value and the represented value—if the value is equidistant from two minifloats, you may write either one). Recall that minifloat is a made-up 8- floating point format with 1 sign bit, 4 exponent , and 3 mantissa bits. a) (3pts) Can $2.75 be exactly represented in minifloat? (circle) YES NO

2.75 or nearest =

Scratch work space:

b) (3pts) Can $100 be exactly represented in minifloat? (circle) YES NO

100 or nearest =

Scratch work space:

c) (6pts) As you know, an unsigned int on our system is 32 bits or 4 bytes. We can imagine separating the number into bytes and stacking the bytes vertically, like this (for 0xFEFAFE05): 11111110 11111010 11111110 00000101 We say a “column” in this view is “odd” if it contains an odd number of 1’s. Write a function odd_cols that takes an unsigned int and returns true if every column of the input number is odd, otherwise false (i.e., returns false if any column with zero, two, or four 1’s in it).  Example 1: odd_cols should return true for the input shown above because the rightmost column has three 0’s and one 1, and all other columns have three 1’s).  Example 2: return false for this input: 0x00000001  Example 3: return true for this input: 0x000000FF  For full credit, your code should separate the bytes and then use a small number of bitwise operations that in effect check all 8 columns simultaneously. In particular, your code should not use any loops (evading this restriction with recursion or excessive repetition is not allowed). Correct solutions that do not follow this guideline are worth 4pts (2pt deduction).  Some code structure is provided to help you get started. o The ptr variable is intended to help you separate out the rows, but you aren’t required to use it. o The solution to this problem does not depend on the byte order, so you shouldn’t be concerned with little-endian issues, and you may assign the provided rowN variables in any order. o You are required to fill in the rowN variable lines so that the variables collectively hold all four bytes, but after that it’s up to you to design your code.

(Write your code on the next page.)

bool odd_cols(unsigned int n) { unsigned char *ptr = (unsigned char*)&n; unsigned char row0, row1, row2, row3;

row0 = ______;

row1 = ______;

row2 = ______;

row3 = ______;

// Write the rest of the function here:

}

Problem 3: Assembly (11 points) Consider the following x86-64 code output by gcc using the settings we use for this class:

000000000040055d : 40055d: push %rbp 40055e: push %rbx 40055f: sub $0x8,%rsp 400563: mov %rdi,%rbp 400566: mov %rsi,%rbx 400569: mov %rdi,%rsi 40056c: mov $0x400674,%edi 400571: mov $0x0,%eax 400576: callq 40057b: movslq %eax,%rdx 40057e: cmp %eax,0x0(%rbp,%rdx,4) 400582: jg 400590 400584: jmp 400595 400586: movslq %eax,%rdx 400589: movb $0x43,(%rbx,%rdx,1) 40058d: add $0x1,%eax 400590: cmp $0x18,%eax 400593: jle 400586 400595: movslq 0x10(%rbp),%rax 400599: add %rbx,%rax 40059c: add $0x8,%rsp 4005a0: pop %rbx 4005a1: pop %rbp 4005a2: retq

Notes: 0x400674 is the address of the string literal "%d" The function signature for scanf is on the reference page at the end of the exam

(a) (1pt) You aren’t expected to have memorized the precise ASCII value of 'C', but you should be able to infer it given the x86-64 code above and the C code in part (b), below. What is the ASCII value of 'C', written in hexadecimal? You may find it convenient to just solve part (b) first. ______

(b) (10pts) Fill in the C code below so that it is consistent with the x86-64 code on the previous page. The first blank is for the types of an argument. Choose a type that would best fit based on register widths and clues in the layout of the C code below, and do not do any casting anywhere. Your C code should fit the blanks as shown, so do not try to squeeze in additional lines or otherwise circumvent this (this may mean slightly adjusting the syntax or style of your initial decoding guess to an equivalent version that fits).

char *ham(int peggy[], ______aaron) {

int george = ______;

if (george < ______) {

for (int i = ______; i < ______; i++) {

______= 'C'; } }

return ______; }

Reference Page

Misc. Functions int scanf(const char *format, ...); int printf ( const char * format, ... ); int sprintf ( char * str, const char * format, ... ); void *memcpy(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n); void *memset(void *ptr, int value, size_t num); void *malloc(size_t size); void *realloc(void *ptr, size_t size); void free(void *ptr); size_t strlen(const char *s); char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n); char *strdup(const char *s); char *strcat(char *dest, const char *src); char *strchr(char *str, int character); char *strtok(char *str, const char * ); int strcmp(const char *str1, const char *str2 ); int strncmp(const char *str1, const char *str2, size_t n);