QuestionQuestion

Transcribed TextTranscribed Text

1. Optimization and Compilers There are at least 4 optimizations that can be made in optimizeMe(). Find four optimization and for each: a. do it, b. tell whether the compiler or programmer should make it, c. tell why either the compiler or programmer (as opposed to the other) should make it // PURPOSE: To sort array 'intArray' of length 'intArrayLen'. Has the // // extern void same effect as 'efficientQuickSort()', but expected to run slower. No return value. inefficientBubbleSort (int intArrayLen, int* intArray ); // I will spare you the irrelevant details // PURPOSE: To sort array 'intArray' of length 'intArrayLen'. Has the // // extern void same effect as 'inefficientBubbleSort()', but expected to run faster. No return value. efficientQuickSort (int intArrayLen, int* intArray ); // I will spare you the irrelevant details // PURPOSE: To harass Computer Systems II students. Computes some arbitrary // function of 'intArrayLen' and 'intArray' that I pulled out of my a**. // Returns its value. int optimizeMe ) inefficientBubbleSort(intArrayLen,intArray); for (i = 0; i < intArrayLen-1; i++) { int diff = intArray[i+1] - intArray[i]; { int i; = 0; int sillySum if (diff == (i % 16)) sillySum += diff * 4; } return(sillySum); } Num Optimitization (just do above) (i) (ii) (iii) (iv) Compiler or Programmer? Why done by the person (or program) you said? (int intArrayLen, int* intArray 2. Memory Consider a process running the following program: #include #include int int main { <stdlib.h> <stdio.h> globalInt () = 10; int i; for (i = globalInt; i != 0; i--) printf("i = %d\n",i); printf("All done!\n"); return(EXIT_SUCCESS); } Please tell where the following objects are stored in memory. Your choices are: (a) ROM BIOS (f) .data segment (b) kernal Memory (the OS) (g) .bss segment (c) shared library memory (h) the heap (d) .text segment (i) the stack (e) .rodata segment Where is: 1. the memory for variable 'i'? 2. the memory for variable 'globalInt'? 3. the for loop? 4. the code that turns the string "i = %d\n" to "i = 6\n" 3. Processes, Exceptions and Signals a. A parent process fork()ed a child process to create some large object. The child process wants to give the object back to the parent. Can this easily be done by signals? If yes, say how If no, say why not and give an alternative b. A parent process fork()s a child process. The child continues running the same program as the parent (it does not do a execl() or similar system call). Is the best way that the parent can give a data structure created before the fork() to the child by writing it to a file and having the child read that file? If so, why? If not, why not? c. Let us say you write a program to measure how quick a person's fingers are by trapping SIGINT and then asking them to press Ctrl-C as rapidly as possible. The SIGINT signal handler increments a global counter every time Ctrl-C is typed. After a predefined time it stops and prints the global counter divided by the time used. What is a fundamental problem with this program? d. What is a zombie process? Are zombie processes bad because they use a lot of CPU time? How can a good programmer avoid having too many zombie processes? 4. Threads The program below makes two child threads: a guessing thread and an answering thread. It uses 3 global integers, 1 pthread_mutex_t, and 2 pthread_cond_t turn: Tells whose turn it is, either ANSWERER_TURN or GUESSER_TURN. guess: Holds the most recent guess generated by the guessing thread. shouldContinue: Holds 1 while the program should continue (the guesser does not have the correct number). Holds 0 after the guesser guesses the correct number. lock: a pthread_mutex_t variable. guessersTurn: a pthread_cond_t variable. answerersTurn: a pthread_cond_t variable. Output: $ ./guesser (Don't tell, but the answer is 7) Is the answer 6? Sorry, the answer is not 6 Is the answer 9? Sorry, the answer is not 9 Is the answer 19? Sorry, the answer is not 19 Is the answer 17? Sorry, the answer is not 17 Is the answer 31? Sorry, the answer is not 31 Is the answer 10? Sorry, the answer is not 10 Is the answer 12? Sorry, the answer is not 12 Is the answer 9? Sorry, the answer is not 9 Is the answer 13? Sorry, the answer is not 13 Is the answer 26? Sorry, the answer is not 26 Is the answer 11? Sorry, the answer is not 11 Is the answer 18? Sorry, the answer is not 18 Is the answer 27? Sorry, the answer is not 27 Is the answer 3? Sorry, the answer is not 3 Is the answer 6? Sorry, the answer is not 6 Is the answer 28? Sorry, the answer is not 28 Is the answer 2? Sorry, the answer is not 2 Is the answer 20? Sorry, the answer is not 20 Is the answer 24? Sorry, the answer is not 24 Is the answer 27? Sorry, the answer is not 27 Is the answer 8? Sorry, the answer is not 8 Is the answer 7? Congratulations! The answer is 7 Please finish the program. One child thread should run answerer(), the other should run guesser(). The two threads should take turns: the guessing thread should make a guess and then the answering thread should compare it with answer (a local variable that only it has). If the guesser got the wrong number, then the guesser should go again. Etc. I have finished main(), which has initializes all objects. Please finish answerer() and guesser(). The vPtr argument is NULL and may be ignored. However, please figure out: What needs to be protected. Where should the locks and unlock go?. Where should conditions and signals go. /* * */ #include <stdlib.h> #include <stdio.h> #include <pthread.h> #define ANSWERER_TURN #define GUESSER_TURN int turn int guess int shouldContinue = 1; pthread_mutex_t lock; pthread_cond_t guessersTurn; pthread_cond_t answerersTurn; guesser.c Joseph Phillips void* answerer { (void* vPtr) int answer = rand() % 32; printf("(Don't tell, but the answer is %d)\n",answer); while (1) { (a) YOUR CODE HERE while (turn != ANSWERER_TURN) { (b) YOUR CODE HERE } if (guess == answer) { printf("Congratulations! The answer is %d\n",answer); shouldContinue = 0; 0 1 = GUESSER_TURN; = -1; turn = GUESSER_TURN; (c) YOUR CODE HERE (d) YOUR CODE HERE break; } else printf("Sorry, the answer is not %d\n",guess); turn = GUESSER_TURN; (e) YOUR CODE HERE (f) YOUR CODE HERE } return(NULL); } void* guesser { while (1) { (g) YOUR CODE HERE (void* vPtr) while (turn != GUESSER_TURN) { (h) YOUR CODE HERE } if ( !shouldContinue ) break; guess = rand() % 32; printf("Is the answer %d?\n",guess); turn = ANSWERER_TURN; (i) YOUR CODE HERE (j) YOUR CODE HERE } return(NULL); } int { pthread_t pthread_t main () answererId; guesserId; pthread_mutex_init(&lock,NULL); pthread_cond_init(&answerersTurn,NULL); pthread_cond_init(&guessersTurn,NULL); pthread_create(&answererId,NULL,answerer,NULL); pthread_create(&guesserId, NULL,guesser, NULL); pthread_join(answererId,NULL); pthread_join(guesserId,NULL); pthread_mutex_destroy(&lock); pthread_cond_destroy(&answerersTurn); pthread_cond_destroy(&guessersTurn); } 5. Practical C Programming a. Why should we use snprintf() instead of sprintf(), strncpy() instead of strcpy(), etc.? Seriously, how bad can using sprintf(), strcpy(), etc. be? b. What does extern mean?What does it tell the compiler to do? c. The program below will compile well but run poorly. Please make it do error checking and fix it to make it proper #include #include #include #include #include #define int main { char* filename char lookFor int fd int count char* buffer; int numBytes; int i; <stdlib.h> <stdio.h> <sys/types.h> <sys/stat.h> <fcntl.h> BUFFER_LEN // for open() // for open() // for open() 256 (int argc, char* argv[] ) = argv[1]; = *argv[2]; = open(filename,O_RDONLY,0); = 0; while ( (numBytes = read(fd,buffer,BUFFER_LEN)) > 0) for (i = 0; i < numBytes; i++) if (buffer[i] == lookFor) count++; printf("%c was found %d times.\n",lookFor,count); return(EXIT_SUCCESS); } 6. Sockets and Files Finish the server function below which counts how many times ordinary ASCII characters (with values from 32 to 127) occur in a given file. The server should do one read() from the client into a buffer to get a filename from the client. Protocol: (Character ' ' appears in client.c 228 times. '!' appears 3 times. '"' appears 14 times. etc. ) server client || | client.c | (Count the ordinary ASCII chars in in client.c) |<----------------------| || (server || counts) | | || | 228 | (count for char 32 ' ' sent back in network endian) |---------------------->| | 3 | (count for char 33 '!' sent back in network endian) |---------------------->| | 14 | (count for char 34 '"' sent back in network endian) |---------------------->| ... | 0 |---------------------->| | 0 | (count for char 127 'DEL' sent back in network endian) |---------------------->| Sample Output: $ ./client Machine name (e.g. localhost)? localhost Port number? 2000 Please enter a filename: client.c : 228 !: 3 ": 14 #: 2 ... }: 4 ~: 0 ^?: 0 The function handleClient(void* vPtr) is run in its own thread. It receives vPtr which points an integer file descriptor for talking to the client. It should: A. Cast vPtr to type int* and set clientFd to the integer passed B. free() pointer vPtr. C. Get a buffer of text from the client and put it into buffer[]. D. open() for reading the file whose name is in buffer[] and put the file descriptor in fileFd. E. Set the histogram counts to 0. (I did this for you.) F. In a loop, read() from fileFd into buffer[]. Make numChars equal to the number of chars read into buffer[]. | (count for char 126 '~' sent back in network endian) G. Count the chars. (I did this for you.) H. Close fileFd. I. Send all HISTOGRAM_LEN values of histogram[] back to the client in network endianness! J. Close clientFd. K. Return NULL. Do not worry about error checking! #define BUFFER_LEN 256 #define HISTOGRAM_LEN 96 void* handleClient { (void* vPtr) char buffer[BUFFER_LEN]; int histogram[HISTOGRAM_LEN]; int clientFd int fileFd; int numChars; int i; // (b) // (c) // (d) = 0; // (a) <-- change that 0 // (e) Already done for (i = 0; i < HISTOGRAM_LEN; i++) histogram[i] = 0; while ( /* (f) { for (i = 0; i < numChars; i++) { // (g) Already done char c = buffer[i]; if ((c>=32)&&(c<=127)) histogram[c-32]++; } } // (h) for (i = 0; i < HISTOGRAM_LEN; i++) { // (i) } // (j) // (k) } */ ) 1. Optimization and Compilers There are at least 4 optimizations that can be made in optimizeMe(). Find four optimization and for each: a. do it, b. tell whether the compiler or programmer should make it, c. tell why either the compiler or programmer (as opposed to the other) should make it // PURPOSE: To compute and return the median value in array 'intArray' of // length 'intArrayLen'. (I will spare you the irrelevant details). extern int getMedianValue (const int* intArray, unsigned int intArrayLen ); // PURPOSE: To harass Computer Systems II students. Computes and returns // some arbitrary and presumably useless-ass function of its arguments. int {int i; int sum optimizeMe = 0; (const int* unsigned int const int* )unsigned int intArray0, intArray0Len, intArray1, intArray1Len for (i = 0; i < intArray0Len - 1; i++) { if (intArray0[i] < intArray0[i+1]) sum += getMedianValue(intArray1,intArray1Len); else sum = sum % 8; } } return(sum * 4); Programmer? Why done by the person (or program) you said? Optimitization (just Compiler or Num do above) (i) (ii) (iii) (iv) 2. Memory Consider a process running the following program: #include #include #include const int const char* int <stdlib.h> <stdio.h> <string.h> BUFFER_LEN stringPtr main = 256; = "Where am I?"; () { char buffer[BUFFER_LEN]; strcpy(buffer,stringPtr); printf("%s\n",buffer); return(EXIT_SUCCESS); } Please tell where the following objects are stored in memory. Your choices are: (a) ROM BIOS (b) kernal memory (the OS) (c) shared library (glibc) (d) .text segment (e) .rodata segment (g) .bss segment (i) the stack Where is: 1.the memory for (f) .data segment (h) the heap variable stringPtr? 2. the memory to which stringPtr points? 3. the memory for variable buffer? 4. the code for strcpy() that copies "Where am I?" into buffer? 3. Processes, Exceptions and Signals Two spys want to break into an office, break into the safe in the office, photograph a book of codes, and then leave. Spy1 breaks into the office, makes spy2, and stays by the door to make sure they don't get caught. Spy2 goes to the safe and tries all opening combinations. If spy1 sees that they are about to get caught then it sends SIGTERM to spy2 to tell it to abort the mission and leave. When spy2 receives SIGTERM then it does abortMission() which prints how many combinations it tried, and then quits returning EXIT_SUCCESS to the OS. If spy2 finds the combination then it prints the combo, sends SIGUSR1 to spy1, and quits. When spy1 receives SIGUSR1 it does successfullyPhotographedDocuments() which prints a message and then quits returning EXIT_SUCCESS to the OS. Please implement the forking, signaling, etc. for spy1.c and spy2.c. YOU ONLY HAVE TO WRITE CODE WHERE IT SAYS YOUR CODE HERE! /* * spy1.c */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> Joseph Phillips #define INVERSE_PROB_GETTING_CAUGHT 100 #define TEXT_LEN 10 // PURPOSE: To tell the user that spy1 is about to go after photographing the // documents and to stop the program while returning EXIT_SUCCESS to the // OS. Ignores 'sig'. No return value. void successfullyPhotographedDocuments (int sig) { printf("Spy1: \"Great now let's go!\"\n"); // YOUR CODE HERE TO WAIT FOR SPY2 AND // STOP THIS PROGRAM, RETURNING EXIT_SUCCESS TO OS } int main (int argc, const char* argv[]) { // I. Applicability validity check: if (argc < 2) { fprintf(stderr,"Usage: spy1 <randNumSeed>\n"); return(EXIT_FAILURE); } // II. Set 2nd spy on his/her way: pid_t spy2Pid = 0; // YOUR CODE HERE TO MAKE A CHILD PROCESS (change the 0) if (spy2Pid < 0) { fprintf(stderr, "It's too busy to spy today -- too many people are watching!\n" ); return(EXIT_FAILURE); } else if (spy2Pid == 0) { return(EXIT_FAILURE); } // III. Make sure we're not detected: int randomSeed = atoi(argv[1]); srand(randomSeed); // YOUR CODE HERE TO TELL OS TO RUN successfullyPhotographedDocuments() // AFTER RECEIVING SIGUSR1 while (rand() % INVERSE_PROB_GETTING_CAUGHT > 0) { printf("Spy1: \"Making sure no one is watching\"\n"); fflush(stdout); usleep(500000); } printf("Spy1: \"We're about to get caught -- let's get outta here!\"\n"); fflush(stdout); // YOUR CODE HERE TO SEND SIGTERM TO SPY2, AND WAIT FOR IT TO FINISH // YOUR CODE HERE TO RUN "./spy2", // WITH argv[1] AS A COMMAND LINE ARGUMENT. fprintf(stderr,"Spy1: \"Couldn't find my spy2 partner\"\n"); // III. Finished: return(EXIT_SUCCESS); } /* * spy2.c */ Joseph Phillips #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #define NUM_DIAL_POSITIONS int firstNum; int secondNum; int thirdNum; int numAttempts void randomlyMakeCombo () { firstNum secondNum thirdNum = (rand() % NUM_DIAL_POSITIONS); = (rand() % NUM_DIAL_POSITIONS); = (rand() % NUM_DIAL_POSITIONS); 4 = 0; } /* PURPOSE: To print how many combinations were tried and to stop the program * * */ void while returning EXIT_SUCCESS to the OS. Ignores 'sigNum'. No return value. abortMission (int sigNum) { printf("Spy2: \"Don't wanna get caught -- aborting after %d attempts\"\n", numAttempts ); // YOUR CODE HERE TO RETURN EXIT_SUCCESS TO OS } int main (int argc, const char* argv[]) { // I. Applicability validity check: if (argc < 2) { fprintf(stderr,"Usage: spy2 <randNumSeed>\n"); return(EXIT_FAILURE); } // II. Setup: int randomSeed = atoi(argv[1]); srand(randomSeed); randomlyMakeCombo(); // YOUR CODE HERE TO TELL OS TO RUN abortMission() // AFTER RECEIVING SIGTERM // III. Try to find combo to safe: int i; int j; int k; for (i = 0; i < NUM_DIAL_POSITIONS; i++) for (j = 0; j < NUM_DIAL_POSITIONS; j++) for (k = 0; k < NUM_DIAL_POSITIONS; k++) { numAttempts++; printf("Spy2: \"Trying %d-%d-%d . . .\"\n",i,j,k); usleep(500000); if (i == firstNum && j == secondNum && k == thirdNum) { printf("Spy2: \"Click -- I photographed their codebook." " Let's leave!\"\n" ); // YOUR CODE HERE TO SEND SIGUSR1 TO SPY1 return(EXIT_SUCCESS); } } // IV. Finished: return(EXIT_SUCCESS); } Sample output: [jphillips@localhost Final]$ spy1 1 Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-0 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-1 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-2 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-3 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-1-0 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-1-1 . . ." ... Spy1: "Making sure no one is watching" Spy2: "Trying 3-2-0 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 3-2-1 . . ." Spy1: "Making sure no one is watching" Spy2: "Click -- I photographed their codebook. Let's leave!" Spy1: "Great now let's go!" [jphillips@localhost Final]$ spy1 6 Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-0 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-1 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-2 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-0-3 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-1-0 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-1-1 . . ." ... Spy1: "Making sure no one is watching" Spy2: "Trying 0-3-2 . . ." Spy1: "Making sure no one is watching" Spy2: "Trying 0-3-3 . . ." Spy1: "We're about to get caught -- let's get outta here!" Spy2: "Don't wanna get caught -- aborting after 16 attempts" 4. Threads a. (Thread routines look like void* threadRoutine (void* vPtr). Why do they take type void*? Why do they return type void*? b. Why do pthread_cond_t conditions exist? They are not mutual exclusion, that is done by pthread_mutex_t locks. So, what problem do they solve? c. (8 Points) You are writing a multi-agent adventure game. There are one or more Player agent objects, each under the control of its own user. There is an autonomous Dragon agent object, that makes its own moves and decisions. There is an autonomous Thief agent object, that makes its own moves and decisions. There is an Environment object, that is passive. Agent objects may make changes to it (e.g. pick up a sword, drop a bag-of-gold), but the Environment object does not change itself. How would you program this with threads? Do not write code, but tell: I. Which objects should be given their own threads. II. How you would solve the problem of two agents reaching for the bag-of-gold at approximately the same time? Only one of them should get it. 5. Practical C Programming a. Why should we use snprintf() instead of sprintf(), strncpy() instead of strcpy(), etc.? Seriously, how bad can using sprintf(), strcpy(), etc. be? b. What does extern mean?What does it tell the compiler to do? c. The program below will compile well but run poorly. Please make it do error checking and fix it to make it proper: #include #include #include const int int main { while (1) { <stdlib.h> <stdio.h> <string.h> LINE_LEN (int argc, char* argv[] ) = 1024; const char* const char* FILE* int int char* int = argv[1]; = argv[2]; = fopen(filename,"r"); = strtol(limitNumText,NULL,10); filename limitNumText fp limit haveReachedEnd = 0; line; counter; for (counter = 0; counter < limit; counter++) { if (fgets(line,LINE_LEN,fp) == NULL) { haveReachedEnd = 1; break; } printf(line); } if (haveReachedEnd) break; printf("Press enter to see the next %d lines:",limit); gets(line); } return(EXIT_SUCCESS); } 6. Sockets and Files Finish the server function below which is told the length of a string (an integer in network endian) a string of that length It then iterates over the files of the current directory(named "."), counts how many lines in all those files have that string, and returns that count (an integer in network endian). Both integers are sent in network endianness! Example: If text Bubu appears one time in two different files, and 5 lines in a third file, and I ask how many lines have the text Bubu, the server will send back 7 as in integer in network endian. $ ./client Machine name (e.g. localhost)? localhost Port number? 2000 Please enter a string: Bubu Protocol: server client || | 5 (network endian) | |<----------------------| || | "Bubu" | (5 chars, including the '\0') |<----------------------| || (server || counts) | | || || | 7 (network endian) | ( "Bubu" appears 6 times) |---------------------->| || The function handleClient(void* vPtr) is run in its own thread. It receives vPtr which points an integer file descriptor for talking to the client. It should: A. Cast vPtr to type int* and set clientFd to the integer passed B. free() pointer vPtr. C. Get the value of strLen from the client. Then, change it from network endian to host (this computer) endian. D. Make lookFor point to strLen bytes of heap-allocated memory. Then, get lookFor bytes from the client and put them in lookFor. E. Set dirPtr to read from the current directory ".". F. In a loop, set entryPtr equal to the address of the next entry read from dirPtr. G. Fill statBuffer full of the meta-data about the current entry. H. Look for only those entries that are files. (Already done for you.) I. Set filePtr to a read through lines of the current file. J. Get the line of text from filePtr and put it into line K. Close filePtr L. Close dirPtr and release the memory in lookFor M. Convert the bytes in count to network endianness and send them back to the client. N. Close clientFd (done for you) Do not worry about error checking! #define LINE_LEN 1024 void* handleClient (void* vPtr) { int int int char* // (B) // (C) // (D) struct stat struct dirent* DIR* FILE* char = 0; // (A) <-- Change that 0 = 0; = NULL; statBuffer; entryPtr; dirPtr filePtr; line[LINE_LEN]; clientFd strLen; count lookFor while ( (entryPtr = NULL /* (F) Change the NULL */) != NULL ) { // (G) if ( S_ISREG(statBuffer.st_mode) /* (H) */ ) { filePtr = NULL; // (I) <-- Change that NULL while ( NULL /* (J) Change the NULL */ != NULL) { char* cPtr = line; char* found; while ( (found = strstr(cPtr,lookFor)) != NULL) { count++; cPtr = found + 1; } } // (K) } } // (L) // (M) close(clientFd); return(NULL); } = NULL; // (E) <-- Change that NULL

Solution PreviewSolution Preview

These solutions may offer step-by-step problem-solving explanations or good writing examples that include modern styles of formatting and construction of bibliographies out of text citations and references. Students may use these solutions for personal skill-building and practice. Unethical use is strictly forbidden.

Code optimization

- Compiler perform optimization when it is producing the assembly code.
- The optimizations are done in a structured way therefore compiler can optimize strightforward actions
- In general,
    - Optimization by code motion should be done by programmer
    - example of optimization by code motion

    for(i = 0; i < someValue; i++){
       i += callFunction(a,b);
    }
    return i;

    above code can be optimized to

    x = callFunction(a,b)

    for(i=0; i< someValue; i++){
       i += x;
    }
    return i;

    - VERY_IMPORTANT: However this can only be done when callFunction is a pure function
       - A pure function does not access or modify any global variables.
       - A pure function does not modify the input parameters(modifications to pointer)
       - Output of a pure function solely depend on the input parameters
    - The above reason is why compiler cannot do this optimization by code motion. Compiler optimization scope is limited to
    the current function scope it is compiling. Therefore compiler is unable to determine whether the callFucntion is pure or not
    - However the programmer can know this detail and perform the optimization

    - Optimization by reduction of strength will be done by compiler
    - example of reduction of strength

    - int i = j * 16 --> int i = j << 4
    - int i = j % 16 --> int i = j & 0xF

    - Multiplication/Division by power of two can be easily done bit shifting.
    - Bit shifting is a faster operation than multiplication therefore this is an optimization
    - Compiler is smart to detect these type of optimizations
    - It's better to let compiler do these type of optimization and keep the code in a more human readable form...

By purchasing this solution you'll be able to access the following files:
Solution.zip.

50% discount

Hours
Minutes
Seconds
$160.00 $80.00
for this solution

PayPal, G Pay, ApplePay, Amazon Pay, and all major credit cards accepted.

Find A Tutor

View available C-Family Programming Tutors

Get College Homework Help.

Are you sure you don't want to upload any files?

Fast tutor response requires as much info as possible.

Decision:
Upload a file
Continue without uploading

SUBMIT YOUR HOMEWORK
We couldn't find that subject.
Please select the best match from the list below.

We'll send you an email right away. If it's not in your inbox, check your spam folder.

  • 1
  • 2
  • 3
Live Chats