Section Handout: The Incredibles - Programming Paradigms - 20, Exercises of Programming Paradigms

Introduction to Computer Science. Section Handout Assignment with Solution of Programming Paradigms. The Incredibles. Prof. Cain - Stanford University

Typology: Exercises

2010/2011

Uploaded on 10/11/2011

larryp
larryp 🇺🇸

4.8

(34)

352 documents

1 / 26

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS107 Handout 20
Spring 2008 April 28, 2008
Section Handout
Problem 1: The Incredibles (given on a midterm a few years ago)
Consider the following struct definition:
typedef struct {
int violet;
char *dash[2];
char superboy[4];
} superhero;
static superhero **pixar(superhero *syndrome);
static superhero *theincredibles(short *frozone, superhero elastigirl)
{
frozone += elastigirl.superboy[*frozone];
((superhero *)((superhero *) elastigirl.dash[0])->dash)->violet = 400;
return *pixar(&elastigirl) + 10;
}
Generate code for the entire theincredibles function. Be clear about what assembly
code corresponds to what line.
Problem 2: New Zoo Revue (given on a midterm several years ago)
You are to generate code for the following nonsense code. Don't be concerned about
optimizing your instructions or conserving registers. We don't ask that you draw the
activation records, but it can only help you get the correct answer if you do. Be clear
about what assembly code corresponds to each line of C.
struct human {
int doug;
short emmyjo[2];
};
struct other {
char *freddie;
struct human charlie;
struct human *henrietta;
};
static struct human **AskingQuestions(struct human *heroes);
static struct human **BeingCalm(short *conformity, struct other *gooddeeds)
{
conformity[*conformity] = 0;
gooddeeds += ((struct human *) (gooddeeds->henrietta[0].emmyjo))->doug;
return AskingQuestions((struct human *) &gooddeeds);
}
Generate code for the entire BeingCalm function.
line 1
line 2
line 3
(over)
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a

Partial preview of the text

Download Section Handout: The Incredibles - Programming Paradigms - 20 and more Exercises Programming Paradigms in PDF only on Docsity!

CS107 Handout 20 Spring 2008 April 28, 2008

Section Handout

Problem 1: The Incredibles (given on a midterm a few years ago)

Consider the following struct definition:

typedef struct { int violet; char *dash[2]; char superboy[4]; } superhero;

static superhero **pixar(superhero *syndrome); static superhero *theincredibles(short frozone, superhero elastigirl) { frozone += elastigirl.superboy[frozone]; ((superhero *)((superhero *) elastigirl.dash[0])->dash)->violet = 400; return *pixar(&elastigirl) + 10; }

Generate code for the entire theincredibles function. Be clear about what assembly

code corresponds to what line.

Problem 2: New Zoo Revue (given on a midterm several years ago)

You are to generate code for the following nonsense code. Don't be concerned about

optimizing your instructions or conserving registers. We don't ask that you draw the

activation records, but it can only help you get the correct answer if you do. Be clear

about what assembly code corresponds to each line of C.

struct human { int doug; short emmyjo[2]; };

struct other { char *freddie; struct human charlie; struct human *henrietta; };

static struct human **AskingQuestions(struct human *heroes); static struct human **BeingCalm(short *conformity, struct other gooddeeds) { conformity[conformity] = 0; gooddeeds += ((struct human *) (gooddeeds->henrietta[0].emmyjo))->doug; return AskingQuestions((struct human *) &gooddeeds); }

Generate code for the entire BeingCalm function.

line 1 line 2 line 3

(over)

The assembly code generated by the compilation of AskingQuestions is given below.

Provide a C-code implementation of AskingQuestions , given the constraint that all

local variables must be of type struct human and/or struct human * , and the only

typecast allowed is (struct other *).

SP = SP – 12;

R1 =.2 M[SP + 8];

M[SP + 4] = R1;

R2 = M[SP + 16];

BNE R2, 0, PC + 16;

R3 = M[SP];

R4 = R3 + 8;

M[SP] = R4;

RV = SP + 12;

SP = SP + 12;

RET;

Problem 2: New Zoo Revue (given on a midterm several years ago)

You are to generate code for the following nonsense code. Don't be concerned about

optimizing your instructions or conserving registers. We don't ask that you draw the

activation records, but it can only help you get the correct answer if you do. Be clear

about what assembly code corresponds to each line of C.

struct human { int doug; short emmyjo[2]; };

struct other { char *freddie; struct human charlie; struct human *henrietta; };

static struct human **AskingQuestions(struct human *heroes); static struct human **BeingCalm(short *conformity, struct other gooddeeds) { conformity[conformity] = 0; gooddeeds += ((struct human *) (gooddeeds->henrietta[0].emmyjo))->doug; return AskingQuestions((struct human *) &gooddeeds); }

  • Generate code for the entire BeingCalm function.

// line 1 R1 = M[SP + 4]; // load conformity R2 =.2 M[R1]; // load *conformity R2 = R2 * 2; // manually compute offset from base address R3 = R1 + R2; // manually compute address M[R3] =.2 0; // and write a short 0 there..

// line 2 R1 = M[SP + 8]; // load gooddeeds, remember it R2 = M[R1 + 12]; // load henrietta[0] field R3 = M[R2 + 4]; // load doug field of human struct at emmyjo R4 = R3 * 16; // pointer math on struct other *: quantum is 16 bytes R5 = R1 + R4; // compute new value for gooddeeds M[SP + 8] = R5; // flush back to stack

// line 3 R1 = SP + 8; // remember &gooddeeds SP = SP – 4; // make space for param M[SP] = R1; CALL SP = SP + 4; // clean up space

RET; // leave RV alone, return

line 1 line 2 line 3

  • The assembly code generated by the compilation of AskingQuestions is given below.

Provide a C-code implementation of AskingQuestions , given the constraint that all

local variables must be of type struct human and/or struct human * , and the only

typecast allowed is (struct other *).

SP = SP – 12;

R1 =.2 M[SP + 8];

M[SP + 4] = R1;

R2 = M[SP + 16];

BNE R2, 0, PC + 16; // potentially jumps to instruction loading RV R3 = M[SP]; R4 = R3 + 8; M[SP] = R4; RV = SP + 12; SP = SP + 12; RET;

Answer

static struct human **AskingQuestions(struct human *heroes) { struct human manners; struct human *remainingCalm; manners.doug = manners.emmyjo[0]; if (heroes == NULL) remainingCalm++; return &remainingCalm + 3; }

The struct human is 8 bytes, and pointers are 4 bytes. The SP = SP – 12 line makes

it clear that there are either two or three local variables—one pointer and one

direct structure, or three pointers. The .2 implies that a short resides at byte

offset 8, so that further requires that the first variable be of type struct human , and

therefore the second variable is a pointer.

char *boy; } couple;

vector generateAllCouples(vector *boys, vector *girls) { vector couples; VectorNew(&couples, sizeof(couple), CoupleFree, 0);

Problem 3: packPackets

You’re to write code that traverses a linked list of custom nodes and builds a

dynamically allocated array of bytes large enough to store the meaningful data held by

the linked list. Each node stores one or more packets of raw information, where each

packet is preceded by a two-byte short stating the length (in bytes) of the packet that

follows it. The end of the packet sequence is marked by a two-byte zero, and the four

bytes after that store the address of the next node in the list (or NULL , if the node is the

last in the list). The following node contains three packets of length 20, 10, and 30 bytes,

in that order. The number of bytes making up the entire node is 72.

You’re to write a function called packPackets that, given the address of the first node in

such a list, builds a dynamically allocated byte array where all packets in the linked list

are replicated verbatim, one after another, in the same order they appear in the list. So,

given the following list:

your packPackets function would return the address of the first byte of this dynamically

allocated figure:

Here are some constraints I’m imposing on your implementation.

  • The address passed to packPackets is the address of the first short storing the

number of bytes making up the first packet in the first node.

4 0 NULL

  • Each node alternates between shorts and packets. A two-byte zero marks the end

of the packet sequence in any given node. Every node ends with a four-byte

pointer identifying the location of the next node in the list.

  • You should implement this function iteratively, and your algorithm should

accomplish everything in exactly one traversal. This requires you to call realloc

for each packet you encounter during your one traversal. [Tip: When NULL is

passed as the first argument to realloc , realloc just calls malloc on your behalf.]

This artificial constraint is being imposed so that I can test your understanding of

realloc.

  • For simplicity, you may assume the list contains at least one node, and that each

node contains at least one packet.

  • You needn’t worry about any alignment restrictions at all.
  • You shouldn’t free or modify the original list in any way.
  • Function: packPackets

  • Builds a contiguous array version of the packet list structure according
  • to the explanations provided on the prior page. The parameter passed
  • is of type short *, because the first meaningful piece of information
  • stored in the list is a two-byte short. The return value is of type
  • void *, because the implementation has no type information about the
  • packet data. */

void *packPackets(short *list) {

Solution 2: Matchmaking

vector generateAllCouples(vector *boys, vector *girls) { vector couples; VectorNew(&couples, sizeof(couple), CoupleFree, 0); int i, j; couple item;

for (int i = 0; i < VectorLength(boys); i++) { for (int j = 0; j < VectorLength(girls); j++) { item.boy = strdup(*(char *) VectorNth(boys, i)); item.girl = strdup((char **) VectorNth(girls, j)); VectorAppend(&couples, &item); } }

return couples; }

Solution 3: packPackets

  • Function: packPackets

  • Builds a contiguous array version of the packet list structure according
  • to the explanations provided on the prior page. The parameter passed
  • is of type short *, because the first meaningful piece of information
  • stored in the list is a two-byte short. The return value is of type
  • void *, because the implementation has no type information about the
  • packet data. */

void *packPackets(short *list) { void *image = NULL; int imageSize = 0; while (list != NULL) { int packetSize = *list++; char *data = list; if (packetSize > 0) { image = realloc(image, imageSize + packetSize); memcpy((char *) image + imageSize, data, packetSize); imageSize += packetSize; list = (short *)(data + packetSize); } else { list = *(short **)data; // list = *(void **)data would work too } } return image; }

CS107 Handout 28

Spring 2008 May 12, 2008

Section Handout

RSS News Feed Madness

You're writing a concurrent C program to simulate the chaos at Terman the night that

Assignment 6: News Feed Aggregator comes due. All 10 TAs are there, ready to answer

questions through the night—in fact, the TAs love CS107 students so much that they all stay

until the very last student leaves. All 115 CS107 students come to Terman with what they

assume is just one bug. Each student waits for one of the 20 computers to become available

(and all computers are initially available), and once one becomes available, he logs in,

debugs for a while, and then searches for an available TA (all of whom are initially

available) to look at his code. The TA informs him of the number of bugs in his code. If

there are no bugs, the student rejoices, logs out, and leaves. If his code is still buggy, then

the student goes back to his computer and debugs a little more, and repeats the process. If

the TA ever reports that the number of bugs is 10 or more, the student gives up, logs out

and leaves without finishing.

Each of the 10 TAs sleeps until a student gets her attention. The student shows her his code,

she studies the code for a while, reports the number of bugs back the student, reads some of

her email, and then goes back to sleep. The very last student needs to wake up all the TAs

to tell them that they can all go home. Here is the starting main function for the Terman

Cluster simulation. You cannot change any of this code:

#define NUM_TAS 10 #define NUM_STUDENTS 115 #define NUM_MACHINES 20

void main(void) { int i; InitThreadPackage(false); for (i = 0; i < NUM_TAS; i++) ThreadNew("TA", TA, 1, i); for (i = 0; i < NUM_STUDENTS; i++) ThreadNew("Student", Student, 0); RunAllThreads(); }

// these simulation functions don't do anything, just "fake" static int Examine(void); // for TA, studies student code, returns bug count static void ReadEmail(void); // for TA, after helping student, before sleeping static void Debug(void) // for Student, to simulate debugging static void Rejoice(void) // for Student, after logging out

Assume the above helpers are already written and are thread safe, you can just call them

when you need to. Your job will be to write the TA and Student functions to properly

synchronize the different activities and efficiently share the common resources. During

section, you’ll all agree what global variables and Semaphores are needed, and then you’ll

continue to write the TA and Student functions.

if (numBugs == 0) Rejoice();

SemaphoreWait(studentsLeftLock); numStudentsLeft--; bool everyoneDone = (numStudentsLeft == 0); SemaphoreSignal(studentsLeftLock); // thought question: why can’t the two lines above be switched?

if (everyoneDone) { for (ta = 0; ta < NUM_TAS; ta++) { SemaphoreSignal(tas[ta].requested); } }

SemaphoreSignal(numMachinesAvailable); }

CS107 Handout 33

Spring 2008 May 19, 2008

Section Handout: All Things Scheme

Problem 1: Building Subsets of a Certain Size

Implement the k-subsets function, which accepts a set and a non-negative integer k and

constructs a list of all those subsets of the incoming set whose size just happens to equal k.

Your implementation should run in time that’s proportional to the number of subsets in the

final answer. In particular, you should not reuse the power-set implementation from lecture

and then filter on length, because that’s entirely too time-consuming when large sets are

paired with small values of k.

;; Function: k-subsets ;; ------------------- ;; k-subsets constructs a list of all those subsets ;; of the specified set whose size just happens to equal k. ;; ;; Examples: (k-subsets '(1 2 3 4) 2) - > ((1 2) (1 3) (1 4) (2 3) (2 4) (3 4)) ;; (k-subsets '(1 2 3 4 5 6) 1) - > ((1) (2) (3) (4) (5) (6)) ;; (k-subsets '(a b c d) 0) - > (()) ;; (k-subsets '(a b d d) 5) - > ()

(define (k-subsets set k) (

Problem 2: Up Down Permutations

a. An up-down list is a homogeneous list which alternates between local minima and local

maxima—that is, the second element is larger than the first and third, the third element is

smaller than the second and fourth, the fourth element is larger than the third and fifth,

and so on. Informally, the list zig-zags up and down as you march over all of its elements.

Using car-cdr recursion, implement the is-up-down routine, which returns #t if and only if

the specified list of atoms is an up-down list according to the specified predicate. List of

length 0 and 1 are automatically considered to be up-down lists.

;; Function: is-up-down? ;; --------------------- ;; Returns true if and only if the specified list is an up-down list ;; according to the specified predicate. ;; ;; Examples: (is-up-down? '() <) - > #t ;; (is-up-down? '(1) <) - > #t ;; (is-up-down? '(1 2 2 3) <) - > #f ;; (is-up-down? '(1 6 2 4 3 5) <) - > #f ;; (is-up-down? '(1 6 2 4 3 5) >) - > #f ;; down-up, but not up-down ;; (is-up-down? '(4 8 3 5 1 7 6 2) <) - > #f

(define (is-up-down? list comp) (

CS107 Handout 33S

Spring 2008 May 20, 2008

Section Solution: All Things Scheme

Problem 1: Building Subsets of a Certain Size

;; Function: k-subsets ;; ------------------- ;; k-subsets constructs a list of all those subsets ;; of the specified set whose size just happens to equal k. ;; ;; Examples: (k-subsets '(1 2 3 4) 2) -> ((1 2) (1 3) (1 4) (2 3) (2 4) (3 4)) ;; (k-subsets '(1 2 3 4 5 6) 1) -> ((1) (2) (3) (4) (5) (6)) ;; (k-subsets '(a b c d) 0) -> (()) ;; (k-subsets '(a b d d) 5) -> ()

(define (k-subsets set k) (cond ((eq? (length set) k) (list set)) ((zero? k) '(())) ((or (negative? k) (> k (length set))) '()) (else (let ((k-subsets-of-rest (k-subsets (cdr set) k)) (k-1-subsets-of-rest (k-subsets (cdr set) (- k 1)))) (append (map (lambda (subset) (cons (car set) subset)) k-1-subsets-of-rest) k-subsets-of-rest)))))

Problem 2: Up Down Permutations

a.

;; Function: is-up-down? ;; --------------------- ;; Returns true if and only if the specified list is an up-down list ;; according to the specified predicate. ;; ;; Examples: (is-up-down? '() <) -> #t ;; (is-up-down? '(1) <) -> #t ;; (is-up-down? '(1 2 2 3) <) -> #f ;; (is-up-down? '(1 6 2 4 3 5) <) -> #f ;; (is-up-down? '(1 6 2 4 3 5) >) -> #f ;; (is-up-down? '(4 8 3 5 1 7 6 2) <) -> #t

(define (is-up-down? ls comp) (or (null? ls) (null? (cdr ls)) (and (comp (car ls) (cadr ls)) (is-up-down? (cdr ls) (lambda (one two) (comp two one))))))

Notice the above version uses tradition car-cdr recursion, but constructs an anonymous

binary predicate out of the original by just switching the roles of the two arguments. (This

is how I got > and not >= from < .) Of course, the disadvantage of this implementation is

that layers of anonymous lambda s build up around the original for arbitrarily large lists.

The solution here is to employ some arm’s length recursion by ensuring that the first three

elements are low-high-low and then recurring on the cdr of the cdr using the original

predicate.

(define (is-up-down? ls comp) (or (null? ls) (null? (cdr ls)) (and (comp (car ls) (cadr ls)) (or (null? (cddr ls)) (and (comp (caddr ls) (cadr ls)) (is-up-down? (cddr ls) comp))))))

You could even use mutual recursion and define a sister is-down-up? function. In fact,

the second half of this problem does exactly that. 

b.

;; Function: up-down-permute ;; -------------------------- ;; up-down-permute generates all those permutations of a list that ;; just happen to be up-down permutations. ;; ;; Examples: (remove 3 '(1 2 3 4 5 4 3 2 1)) -> (1 2 4 5 4 2 1) ;; (up-down-permute '()) -> (()) ;; (up-down-permute '(1)) -> ((1)) ;; (up-down-permute '(1 2)) -> ((1 2)) ;; (up-down-permute '(1 2 3)) -> ((1 3 2) (2 3 1)) ;; (up-down-permute '(1 2 3 4 5)) -> ;; ((1 3 2 5 4) (1 4 2 5 3) (1 4 3 5 2) (1 5 2 4 3) (1 5 3 4 2) ;; (2 3 1 5 4) (2 4 1 5 3) (2 4 3 5 1) (2 5 1 4 3) (2 5 3 4 1) ;; (3 4 1 5 2) (3 4 2 5 1) (3 5 1 4 2) (3 5 2 4 1) ;; (4 5 1 3 2) (4 5 2 3 1))

(define (construct-permute-generator comp inverted-permute ls) (lambda (number) (apply append (map (lambda (permutation) (if (comp number (car permutation)) (list (cons number permutation)) '())) (inverted-permute (remove ls number))))))

(define (up-down-permute ls) (if (<= (length ls) 1) (list ls) (apply append (map (construct-permute-generator < down-up-permute ls) ls))))

(define (down-up-permute ls) (if (<= (length ls) 1) (list ls) (apply append (map (construct-permute-generator > up-down-permute ls) ls))))

Problem 2: Maximizing Points

You’re given an unlimited number of pebbles to distribute across an N x N game board

(N drawn from [3, 15]), where each square on the board contains some positive point

value between 10 and 99, inclusive. A 6 x 6 board might look like this:

The player distributes pebbles across the board so that:

  • At most one pebble resides in any given square.
  • No two pebbles are placed on adjacent squares. Two squares are considered

adjacent if they are horizontal, vertical, or even diagonal neighbors. There’s no

board wrap, so 44 and 61 aren’t neighbors. Neither are 33 and 75.

The goal is to maximize the number of points claimed by your placement of pebbles.

Write a program that reads in a sequence of boards from standard input and posts the

maximum number of points attainable by an optimal pebble placement for each. Each

board is expressed as a series of lines, where each line is a space-delimited series of

numbers. A blank line marks the end of each board (including the last one.)

The better solution to this problem uses memoization to reduce the running time of the

solution from something very exponential in running time to something noticeably less

exponential (though still exponential.) Don’t worry too much about the file reading

portion of the solution—focus instead on the ideal distribution of pebbles and the

Python code that helps to discover it. (See the last page of this handout for a list of all

dictionary and mutable sequence methods.)

So, if the following were fed to standard input:

then your program would print the maximum number of points one can get by

optimally distributing pebbles while respecting the two rules, which would be this: