Eroxl's NotesGraph
Practice Final Exam 3 - CPSC 213

Problem 1

struct U {
    short p;
    char  q[5];
    int   r;
    char  s;
} *u = (struct U*) 0x5000;

Evaluate each expression. Give answers in hexadecimal and explain any sign or zero extension. Remember that pointers are 8 bytes long.

(a). What is sizeof(*u)? Give Your Answer as an Integer

(b). What is &(u->r)? Give Your Answer as a Hex Number

Assume a Big-Endian machine.

int x = 0x3f9a6b21;
char *cp = (char*) &x;

(c). What is cp[3]? Give Your Answer as a Hex Number

Problem 2

int *p;
int  q[12];

For each of the following C statements, indicate the minimum number of memory locations that need to be read from in order to execute the statement, excluding the reading of the instructions themselves. Stores into memory are not counted.

(a). q[q[4]] = p[1]

(b). p[2] = 7

(c). q[p[0]] = p[q[2]]

(d). q[3] = p[p[q[1]]]

(e). p[p[q[0]]] = p[2] + p[q[0]]

Problem 3

struct C {
    int      *p;
    int       j[1];
    struct D  d;
} c;

struct D {
    int       *p;
    int        j[1];
    struct C  *c;
} *d;

Translate the Following C Code to SM213 Assembly. Use Labels to Refer to the Memory Address of Each Variable

d->c->d.p = c.d.c->j;

Problem 4

Part A. Show Memory State after Each Statement

int A[5] = {1, 2, 3, 4, 5};
int *p    = &A[1];
int *q    = &A[3];
int **r   = &p;

*q = *p + 2;
r = &q;
*(*r - 1) = **r + *p;

Part B. Harder Version

int A[6] = {1, 2, 3, 4, 5, 6};
int *p    = &A[1];
int *q    = &A[4];
int **r   = &p;
int ***s  = &r;

*q = *p + A[0];
*(*r + 2) = *q - *p;
r = &q;
*(*r - 2) = **r + A[2];
p = &A[0];
**s = p;
*(*r + 1) = *p + *(*s);
*(*r - 3) = *(*r + 1) + **r;

Problem 5

For each question, choose the best classification of the code. Possible answers: memory leak; dangling pointer; memory leak and dangling pointer; array overflow; no bug; poor modular structure; no bug; good modular structure.

(a). Question A

// in module study
int *study_think(int n) {
    int *p = malloc(sizeof(*p) * n);
    for (int i = 0; i < n; i++)
        p[i] = i;
    return p;
}

// in module relax
int relax_review() {
    int *x = study_think(100);
    free(x);
    int s = 0;
    for (int i = 0; i < 100; i++)
        s += x[i];
    return s;
}

(b). Question B

// in module record
int *record_make(int n) {
    int *p = malloc(sizeof(*p) * n);
    for (int i = 0; i < n; i++)
        p[i] = i + 1;
    return p;
}

// in module report
int report_sum() {
    int *x = record_make(80);
    int s = 0;
    for (int i = 0; i < 80; i++)
        s += x[i];
    return s;
}

(c). Question C

// in module plan
int *plan_make(int n) {
    int *p = malloc(sizeof(*p) * n);
    for (int i = 0; i < n; i++)
        p[i] = i;
    return p;
}

// in module score
int score_sum() {
    int *x = plan_make(60);
    int s = 0;
    for (int i = 0; i <= 60; i++)
        s += x[i];
    free(x);
    return s;
}

(d). Question D

// in module store
int *store_last = NULL;

void store_save(int *x) {
    if (store_last)
        rc_free_ref(store_last);
    store_last = x;
}

// in module compute
int compute_total() {
    int *p = rc_malloc(sizeof(*p));
    *p = 5;
    store_save(p);
    rc_free_ref(p);
    return *p;
}

(e). Question E

// in module cache
int *cache_ptr = NULL;

void cache_set(int *x) {
    cache_ptr = x;
    rc_keep_ref(cache_ptr);
}

// in module worker
void worker_run() {
    int *p = rc_malloc(sizeof(*p));
    *p = 10;
    cache_set(p);
    rc_free_ref(p);
}

Problem 6

Translate the Following Code to SM213 Assembly

if (x > y)
    z = x - y;
else
    z = y - x;

Problem 7

Write SM213 Assembly Including Prologue and Epilogue for the Following Procedure

int foo(int *a, int b) {
    int *c;
    int  d;
    c = &b;
    bar();
    return *c;
}

Problem 8

F0: deca r5
    st   r6, 0(r5)
    deca r5
    st   r1, 0(r5)
    deca r5
    st   r2, 0(r5)
    ld   $5,  r1
    mov  r0,  r2
L0: beq  r1,  L1
    add  r2,  r2
    dec  r1
    br   L0
L1: mov  r2,  r0
    ld   0(r5), r2
    inca r5
    ld   0(r5), r1
    inca r5
    ld   0(r5), r6
    inca r5
    j    (r6)

(a). Identify All Parts of the Code (Function Calls, Prologues/Epilogues, Static Control Flow Elements). For All Branch Instructions Write the Machine Code, e.g. 0xA123

(b). Write Equivalent C Code for F0

Problem 9

int run(int (*ops[])(int, int (*next)()), int n) {
    int result = 0;
    for (int i = 0; i < n; i++)
        result = opsi;
    return result;
}

The parameter ops is an array of function pointers. Each element of ops is a function of type int (*proc)(int, int (*)()) that takes an integer argument, takes a callback function next as a second argument, and returns an integer.

Assume that int next_value(); returns a random integer each time it is called.

The following program uses run to print the maximum of three random numbers.

int first(int acc, int (*next)()) {
    return next();
}

int main() {
    int (*op_list[])(int, int (*)()) = {first, max_acc, max_acc, print_acc};
    printf("%d\n", run(op_list, 4));
}

print_acc has already been implemented correctly so that it prints the value of acc and then returns that same value.

The call sequence {first, max_acc, max_acc, print_acc} should behave like this: first gets the first random number, the first call to max_acc compares that value with a second random number, the second call to max_acc compares the current maximum with a third random number, and print_acc prints the final maximum.

Implement max_acc so that the Program Prints the Maximum of Three Random Numbers

Requirements:

  • You may call next() as many times as needed.
  • Your implementation must use the callback argument rather than accessing any global random-number source directly.
  • Do not modify run, first, or main.
  • Write only the definition of max_acc.
int max_acc(int acc, int (*next)());

Problem 10

void m(int (*f)(int, int), int *a, int *b, int *c, int n) {
    for (int i = 0; i < n; i++)
        c[i] = f(a[i], b[i]);
}

int r(int (*f)(int, int), int *a, int n, int p) {
    for (int i = 0; i < n; i++)
        p = f(a[i], p);
    return p;
}

int fi(int (*f)(int, int), int *a, int *b, int n, int p) {
    int j = 0;
    for (int i = 0; i < n; i++) {
        if (f(a[i], p))
            b[j++] = a[i];
    }
    return j;
}

Your solution must not directly call any procedures other than m, r, or fi. You may define your own functions to pass as parameters. Your code must not contain any loops — do not use for, while, or goto anywhere in your code, including comments. You may call any of the procedures multiple times, may include basic arithmetic operations on individual values, and may allocate memory on the heap as needed.

(a). Part A

Starting with two arrays of n integers, a and b, allocate and compute a new array c such that c[i] = a[i] > b[i] ? 1 : 0. Also compute and return the total number of 1s in c.

int q2(struct q2_args_s args) {
    int *a = args.a;
    int *b = args.b;
    int  n = args.n;
    // TODO: your code here
    int *c;
    int  total;
    // ====================
    return total;
}

(b). Part B

Starting with an array a of n integers, allocate a new array b containing only the elements of a whose absolute value is greater than 10. Also return the sum of the elements copied into b.

For example, if a = {3, -12, 8, 15, -20} then b = {-12, 15, -20} and sum = -17.

int q3(struct q3_args_s args) {
    int *a = args.a;
    int  n = args.n;
    // TODO: your code here
    int *b;
    int  sum;
    // ====================
    return sum;
}

(c). Part C

Starting with two arrays of n integers, a and b, allocate a new array d such that d[i] = a[i] - b[i]. Then allocate a second array e containing only the nonzero values from d. Return the number of elements stored in e.

int q4(struct q4_args_s args) {
    int *a = args.a;
    int *b = args.b;
    int  n = args.n;
    // TODO: your code here
    int *d;
    int *e;
    int  n_nonzero;
    // ====================
    return n_nonzero;
}

Problem 11

Assume all global variables are shared by all threads, mx is a mutual exclusion lock, c1 and c2 are condition variables associated with mx, each printf prints its character immediately and exactly once with no spaces or newlines unless shown, and all threads execute exactly once. v1 and v2 are global variables initialized to 0.

For each part, list all possible strings that could be printed to the screen. Write each answer as a string such as ACDB.

(a). Scenario 1

Thread 1:

uthread_mutex_lock(mx);
printf("A");
if (!v1) {
    uthread_cond_wait(c1);
}
printf("B");
uthread_mutex_unlock(mx);

Thread 2:

uthread_mutex_lock(mx);
printf("C");
v1 = 1;
uthread_cond_signal(c1);
printf("D");
uthread_mutex_unlock(mx);

(b). Scenario 2

Thread 1:

uthread_mutex_lock(mx);
if (!v1) {
    uthread_cond_wait(c1);
}
uthread_mutex_unlock(mx);
printf("A");
uthread_mutex_lock(mx);
uthread_cond_signal(c2);
if (!v2) {
    uthread_cond_wait(c1);
}
uthread_mutex_unlock(mx);
printf("B");

Thread 2:

printf("C");
uthread_mutex_lock(mx);
v1 = 1;
uthread_cond_signal(c1);
uthread_cond_wait(c2);
uthread_mutex_unlock(mx);
printf("D");
uthread_mutex_lock(mx);
v2 = 1;
uthread_cond_signal(c1);
uthread_mutex_unlock(mx);

(c). Scenario 3

Thread 1:

printf("A");
uthread_mutex_lock(mx);
while (!v1) {
    uthread_cond_wait(c1);
}
printf("B");
v2 = 1;
uthread_cond_signal(c2);
uthread_mutex_unlock(mx);
printf("C");

Thread 2:

uthread_mutex_lock(mx);
printf("D");
v1 = 1;
uthread_cond_signal(c1);
while (!v2) {
    uthread_cond_wait(c2);
}
printf("E");
uthread_mutex_unlock(mx);
printf("F");