Practice Exam

This practice midterm for Winter 2015 CS107 was the actual midterm for Julie Zelenski’s
Autumn 2014.
CS107
J Zelenski
Handout #4
Halloween 2014
Midterm Examination
Your exam should have 6 pages and there are 3 questions worth a total of 70 points. The time
allotted is 75 minutes. Write your answers directly on the exam, including any work that you
wish to be considered for partial credit. The exam is closed-book and closed-device; you may
refer only to your one page of prepared notes. You may use functions from the standard C
libraries unless otherwise restricted in the problem instructions. The last page of the exam is a
list of common function prototypes. Your code does not need #include statements, nor must you
declare prototypes. Comments are not required, but may earn partial credit if your intentions are
correct but your code is wrong. We thank you in advance for writing more neatly than you have
in your entire life.
Name (printed) __________________________________________________________
SUNet username (i.e. myth login) ________________________
NVidia seat location: Row letter (label on armrest at end of your row) _______________
Seat number (label on bottom front edge of seat) _______________
SCPD students: Check here
☐ if you want your graded exam returned via SCPD distribution.
By signing my name, I confirm I will fully abide by the letter and spirit of the Honor Code when
completing this exam.
(signed) ________________________________________________________________
Score
Grader
1. C-strings and generic client
(25) ______
______
2. C generics implementation
(25) ______
______
3. Bits, bytes, and numbers
(20) ______
______
Total
(70) ______
Page 2 of 6
Problem 1: C-strings and client of generic interfaces (25 points)
We define a word's signature to be the string containing the letters of the word in sorted order.
For example, the signature of "apple" is "aelpp" and the signature of "bell" is "bell". Write the
make_map function below to take a CVector of words and fill a CMap with entries mapping each
word (key) to its signature (value). The CVector was created using cvec_create(sizeof(char*),
capacity, cleanup). You can assume the cleanup function is already correctly implemented. To
form a word's signature, sort its letters into alphabetical order. You must use qsort and this will
require that you write an appropriate callback function. You may assume the words consist only
of lowercase letters.
CMap *make_map(const CVector *cv)
{
CMap *cm = cmap_create(sizeof(char*), cvec_count(cv), cleanup);
Page 3 of 6
Problem 2: Implementing generic interfaces (25 points)
Complete the make_list function started below that takes a generic array of elements and creates
a linked list of those same elements. The function's three arguments are the base address of the
array, the number of elements in the array, and the size of each element in bytes.
The function returns a pointer to a linked list of cells, one cell for each element in the array. The
order of the elements in the list is the same as in the array. Each list cell consists of an element of
elemsz bytes and a pointer to the next cell (null if this is the last cell). The element and the
pointer are laid out in contiguous memory as shown below:
void *make_list(const void *arr, int nelems, int elemsz)
{
void *list = NULL;
for (int i = nelems-1; i >= 0; i--) { // prepend ith elem to front of list
Page 4 of 6
Problem 3: Bits, bytes, and numbers (20 points)
a) The discrete binary logarithm, defined for positive N, is the value of log2N rounded down to
an integer. For example, the discrete binary logarithm of 7 is 2. What must the bit patterns of two
integers have in common in order to have the same discrete binary logarithm?
b) Write the integer function dlog to compute the discrete binary logarithm. Use a
straightforward implementation which loops through all the bits.
int dlog(unsigned int n)
{
assert(n > 0);
// n is required to be positive
Page 5 of 6
c) Write the float function dlogf to compute the discrete binary logarithm of a positive float
value. It should accept normalized and denormalized inputs; you may ignore exceptional inputs.
Your implementation must work by manipulating the underlying float bits, using only integer
arithmetic and bitwise operations—no floating point operations or <math.h> functions. You
may call the integer dlog function from part (b) and can assume it works correctly. Hint: it may
help to separate into cases for normalized and denormalized inputs.
int dlogf(float f)
{
assert(f > 0);
unsigned int bits = *(unsigned int *)&f;
// access raw bits
d) Assume that the integer dlog and float dlogf functions work correctly for all valid inputs. For
many float and integer values, the result from dlog((unsigned int)val) will equal
dlogf((float)val), but this equality does not hold for all values.
Assign n below to a constant integer expression greater than 1 such that the result from
dlogf((float)n) disagrees with the correct result from dlog(n).
unsigned int n = ________________________________________________ ;
Assign f below to a constant float expression greater than 1 such that the result from
dlog((unsigned int)f) disagrees with the correct result from dlogf(f).
float f = ________________________________________________ ;
Page 6 of 6
Library functions
Reminder of the prototypes for potentially useful functions. You won't use every function listed. You may also use
standard C library functions not on this list.
size_t strlen(const char *str);
char *strcpy(char *dst, const char *src);
char *strncpy(char *dst, const char *src, size_t n);
char *strcat(char *dst, const char *src);
char *strncat(char *dst, const char *src, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strdup(const char *s);
void *malloc(size_t sz);
void *realloc(void *ptr, size_t sz);
void free(void *ptr);
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
void *memcpy(void *dst, const void *src, size_t n);
void *memmove(void *dst, const void *src, size_t n);
typedef void (*CleanupFn)(void *addr);
CVector
int
void
void
void
*cvec_create(int elemsz, int capacity_hint, CleanupFn fn);
cvec_count(const CVector *cv);
*cvec_nth(const CVector *cv, int index);
*cvec_first(const CVector *cv);
*cvec_next(const CVector *cv, const void *prev);
CMap *cmap_create(int valuesz, int capacity_hint, CleanupFn fn);
void cmap_put(CMap *cm, const char *key, const void *val);