Worksheet: C3 | CS 2113 Software Engineering - Fall 2022

Worksheet: C3

Worksheets are self-guided activities that reinforce lectures. They are not graded for accuracy, only for completion. Worksheets are due by Sunday night before the next lecture.

Note

Attempt to answer these questions before running the code. This will improve your ability to analyize and reason about code without an IDE or compiler. This skill we be helpful on the exams.

Questions

  1. Examine the program below and complete the code.

    #include <stdio.h>
    
    #define NUM_ROWS 3
    #define NUM_COLS 3
    
    int main() {
    
        int matrix[NUM_ROWS][NUM_COLS] = { {2, 5, 1},
                                           {3, 9, 6},
                                           {8, 7, 4}};
    
        // WRITE CODE TO PRINT OUT THE MATRIX
    
    }
    

    Finish the code above so that the output is the following:

    2 5 1 
    3 9 6 
    8 7 4 
    

    Reveal Solution

  2. Examine the program below and complete the code.

    #include <stdio.h>
    
    #define NUM_ROWS 3
    #define NUM_COLS 3
    
    int main() {
    
        int matrix_a[NUM_ROWS][NUM_COLS] = { {2, 5, 1},
                                             {3, 9, 6},
                                             {8, 7, 4}};
    
        int matrix_b[NUM_ROWS][NUM_COLS] = { {4, 1, 6},
                                             {9, 7, 5},
                                             {3, 8, 2}};
    
        int matrix_c[NUM_ROWS][NUM_COLS];
    
        // https://en.wikipedia.org/wiki/Matrix_multiplication_algorithm#Iterative_algorithm
        /*
            For i from 1 to num_rows:
                For j from 1 to num_cols:
                    Let sum = 0
                    For k from 1 to num_cols:
                        Set sum = sum + (Aik * Bkj)
                    Set Cij = sum
        */
        
        // USING THE ALGORITHM ABOVE
        // WRITE CODE HERE TO MULTIPLY THE TWO MATRICES
        // PUT THE RESULT IN MATRIX_C
    
        // PRINT RESULTING MATRIX_C
    }
    

    Finish the code above so that the output is the following:

    56 45 39 
    111 114 75 
    107 89 91 
    

    Reveal Solution

  3. The following function declaration will not compile.

    void foobar( int a[][]);
    

    Provide an explanation for what is wrong and how to fix it.

    Reveal Solution

  4. Examine the program below and answer the following questions.

    #include <stdio.h>
    
    int main() {
        int array[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
    
        printf("%d\n", *(*array + 4));
    }
    

    Attempt to answer these questions without running the code!

    • What is the output of this program?
    • Explain the memory layout of a two-dimensional array?

    Reveal Solution

  5. Examine the program below and answer the following questions.

    #include <stdio.h>
    #include <string.h>
    int main(){
        int a[2][3] = { {10,20,30}, {5,6,7} };
       
        int * p = (int *)a+4;
    
        p[1] = 42;
        //MARK
    }
    

    Attempt to answer these questions without running the code

    • What are the values of a at MARK
    • In plain English, provide a description of how the line int * p = (int *)a+4 works when the array dimensions are int[2][3].
    • Draw the memory diagram at MARK

    Reveal Solution

  6. Examine the program below and answer the following questions.

    int main(){
      int a[][3] = { {10,20,30}, 
                    {5,6,7},
                    {-1,-2,-3},
                    {17,19,21}};
    
      int ** p = &a[1];
      int * q =  &p[1];
      
      q[1] = 42;
      //MARK
    }
    

    Attempt to answer these questions without running the code

    • What are the values of a after at MARK
    • Offer a plain English explanation for what exactly int * q = &p[1] is referring to in a
    • Draw the memory diagram at MARK

    Reveal Solution

  7. Below are the results of two Tic-Tac-Toe games, player o wins game 1 while player x wins game 2. Unfortunately one of the players (x or o) has inserted some evil code to change the boards.

    Run the code below in the C visualizer and answer the questions below.

    #include <stdio.h>
    #include <string.h>
    
    int main() {
      char *game_1[3] = {
        "o|x| ",
        "o|o|x",
        "x|x|o"};
    
    char *game_2[3] = {
          "x|x|o",
          "o|x| ",
          "o|x|o",
      };
      
      //Begin Evil Code
      for (int i = 0; i < 3; i++) {
        char **tmp = &game_1[i];
        game_1[i] = game_2[i];
        game_2[i] = *tmp;
      }
      //End Evil Code
    
      printf("The winner of game 1 is: ...");
      printf("The winner of game 2 is: ...");
    }
    
    • What do you notice about the pointers to the strings on the heap?
    • What did the evil code do to the 2 boards and who inserted the evil code?

    Reveal Solution

  8. Answer the following questions:

    • What does malloc() do? What are the advantages or disadvantages of using malloc(), if any?
    • What is the difference between malloc() and calloc()?

    Reveal Solution

  9. A computer science major who struggles with algebra is trying to modify their grades. The student was able to hack into the administrative code and insert some Evil Code to change their grade.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct {
      char *name;
      char grade;
    } course_t;
    
    int main() {
    
      course_t *courses[3];
    
      courses[0] = malloc(sizeof(course_t));
      courses[0]->name = "Basket Weaving";
      courses[0]->grade = 'A';
    
      courses[1] = malloc(sizeof(course_t));
      courses[1]->name = "Complex Tic Tac Toe Analysis";
      courses[1]->grade = 'A';
    
      courses[2] = malloc(sizeof(course_t));
      courses[2]->name = "Algebra for CS Majors";
      courses[2]->grade = 'D';
    
      //... some admin code
    
      // Begin Evil Code inserted by student
      courses[2] = malloc(sizeof(course_t));
      courses[2]->name = "Algebra for CS Majors";
      courses[2]->grade = 'B';
    
      // Rest of program
      // ...
    
      printf("Your grades for the semester are ...\n");
      // prints grades
      free(courses[0]);
      free(courses[1]);
      free(courses[2]);
    }
    
    • Did the student introduce a memory leak?
    • If so, how many bytes were leaked?
    • Explain the memory leak or why there can’t be a memory leak.

    Reveal Solution

  10. What is the difference between a memory violation and a memory leak? Provide a small code example of each.

    Reveal Solution

  11. Consider the following code

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct {
      char * name;
      short x;
      short y;
    } point_t;
    
    int main() {
      point_t * a = malloc(sizeof(point_t));
    
      char * tmp_name = "Point of Interest";
      a->name = malloc(sizeof(char)*strlen(tmp_name)+1);
      strcpy(a->name, tmp_name); //Copies the string on the right to the left
      a->x = 4;
      a->y = 1;
    
      point_t b;
      b = *a;
      free(a);
    
      printf("%s",b.name); //MARK
      free(b.name);
    }
    

    Attempt to answer these questions without running the code

    • Is printing at the indicated MARK a memory violation?
    • If so, how many bytes of a memory violation occur? If not, explain why there is no violation.
    • Does this program leak any memory?
    • What is the output?

    Reveal Solution

  12. For the next few questions, consider that your implementing a Linked List in C using the following struct

    typedef struct node{
        int val;
        struct node * next;
    
    } node_t;
    typedef struct llist{
       node_t * head;
       int len;    
    } llist_t;
    

    Write the following functions:

    • llist_t * new_list() : allocates a new empty linked list
    • void del_list(llist_t * list) : dealocates a linked list list
    • void add_to_head(llist_t *list,int new_value) : add the new_value to the head of the list.

    Reveal Solution

  13. Referring to the linked list structures above, complete the following functions over these lists without recursive calls (a function calling itself).

    int sum(llist_t * list){
        // return a single integer, 
        // which is the sum of all nodes' val
        
        // FINISH ME
    }
    
    int max(llist_t * list){
        // return a single integer,
        // the maximum val among all the nodes
    
        // FINISH ME
    }
    
    void add_to_tail(llist_t * list, int new_value){
       // Add the new_value to the end of the link list
       
       // FINISH ME
    }
    

    Reveal Solution

  14. Referring to the linked list structures above, complete the following recursive functions over these lists

    
    int sum(llist_t * list){
        return _sum(list->head);
    }
    
    int _sum(node_t * node){
      //FINISH ME!
    }
    
    
    int min(llist_t * list){
        return _min(list->head);
    }
    
    int _min(node_t * node){
      //FINISH ME!
    }
    
    void add_to_tail(llist_t * list, int new_value){
       list->head = _add_to_tail(list->head, new_value);
    }
    
    node_t * _add_to_tail(node_t * node, int new_value){
      //FINISH ME! --- this one is tough!
    }
    
    

    Reveal Solution