Due Wednesday, April 20th, 11:59pm

Goals for this Warmup

  • Practice programming with strings
  • Introduce pointers.

For this lab, you are welcome to get technical help from another student on how to use or install any of the tools involved. You may also get syntax help on C. You may not, however, get help on the algorithmic portion of the exercise outside of office hours or piazza questions to TAs or instructors.

Multi-D Array Allocation

Recall from class that to dynamically allocate a multi-dimensional array, we need to think about them a little differently than before. With static allocation, you think of a 2-d array as a rectangle: a single unit of rows and columns. While useful for us to visualize 2-d arrays, this mental model breaks down with arrays higher than degree 2, and it also breaks down with dynamically allocated arrays.

A more accurate way to think about multi-dimensional arrays is as arrays of arrays. A 2-d array of ints is an array of int arrays. Let's attempt to allocate int i_array[5][10] dynamically.
What type is a dynamically-allocated int array? int*
What type is a dynamically-allocated int* array? int**
Therefore, the type is int**.

int **i_array = NULL;
How do I allocate an array of int*?
i_array = (int **)malloc(sizeof(int*)*5);
Now, each element of i_array is itself an array. This means we need to allocate 5 arrays of ints.
int i;
for(i=0;i<5;i++)
        i_array[i] = (int*)malloc(sizeof(int)*10);
Given this information, you need to generalize in two ways: 1) width and height are variables 2) extend to 3-d arrays

Set up

Remember to create a new directory in your repository for this lab.
$  cd CNET-cs152-spr-16
$  mkdir hw3
$ svn add hw3
$  cd hw3

Duet Programming Setup

Do not forget to copy your finished files from your duet repository into your personal repository.. Your duet repository is https://phoenixforge.cs.uchicago.edu/svn/cs152-spr-16-duet-X. with your own pair number in place of X. Remember to create a new directory in your repository for this lab.
$  cd cs152-spr-16-duet-X
$  svn update  
$  mkdir hw3
$ svn add hw3
$ cd hw3

You will be using the full power of repositories - repositories have two purposes: 1) backup your work in case you accidentally delete something 2) allow two people to work on different files of the same project at the same time. We will use this for both purposes.

At any given time, you should coordinate with your duet partner as to who is editing which file. Whenever your file is in a stable state (you completed something and, depending on the phases, got the compile errors out of it), you commit your file. Whenever you want to get the latest set of stable changes from your partner, you svn update.

Good luck and have fun learning together!

Problems:

During this warmup, you are going to implement several functions that exercise strings and pointers. If you are using Duet Programming, do not forget to trade off after each function. The functions are ordered to provide specific practice to each student.

You are not allowed to use the string library during the warmup. You are allowed to use it in the homework.

Problem 1: count_doubles

Write a function that counts how many double letters there are in a string.

unsigned int count_doubles(char *str);
count_doubles("book") returns 1.
count_doubles("bookkeeper") returns 3.
count_doubles("book weep sleep     ") returns 3.
count_doubles("pleeeeease") returns 2.

Problem 2: str_cat_dup

There is a major limitation with the str_cat function - an array with sufficient memory must be passed into the function. Write a function that accepts two strings, str1 and str2. It allocates memory and populates it to create a single string starting with str1 and ending with str2.

Remember that you cannot use any string functions in this warmup.
You are responsible for adding the string terminating character.
You must allocate exactly the amount of space necessary.

char* str_cat_dup(char *str1, char *str2);
str_cat_dup("hello",".pdf") returns a pointer to "hello.pdf".

Problem 3: grow_array

Write a function that, given an array, will grow the array. You may not call any functions other than malloc/free within this function. You will first create a new array of the right size, then copy over the contents from the first array, then deallocate the first array. Return a pointer to the new array.

The array we'll grow contains pixel structs. Add the pixel struct definition to the warmup3.h file. This allows it to be used in warmup3.c as well as your test_warmup3.c

typedef struct {
  int red, green, blue;
} pixel;

pixel* grow_array(pixel* old_array, unsigned int old_size, 
				unsigned int new_size);

Print an error and return NULL for the following circumstances and DO NOT deallocate the first array:
1) malloc returns NULL
2) new_size <= old_size
If old_size == 0, no error - just don't deallocate the old array.

Problem 4: create_multid_array

Create a function that will allocate and zero out (initialize with all 0's) a multi-dimensional array of ints. You only need to support 1-d, 2-d, and 3-d arrays. I suggest creating helper functions. You are passed the degree (either 1, 2, or 3), and an array of sizes. It returns the address to the beginning of the multi-d array (a pointer). It returns a void* because, depending on the degree, the type of the return value will be different. However, all pointers are the same size, so we don't need to know the type in order to return it.

If someone asks for a 3-d array with size[0] = 5, size[1] = 7, size[2] = 3, then it should create an array that, if allocated as a local variable, would have these dimensions:

int array[5][7][3];
It has the following signature:
void* create_multid_array(unsigned int degree, unsigned int *sizes);

If the user gives a degree of 0 or more than 3, print an error and return NULL. Likewise, if the size value is 0, print an error and return NULL. Finally, if malloc returns NULL, also print an error and return NULL.

Phase 1: Problem Clarification, Test Design

Remember - for each file you create, "touch" it first, then add it to svn. Partner A:
1. Determine exact interfaces for functions. This has already been done for you.
2. Implement the "skeleton" files - main, .h, and .c files.
  • Create warmup3.h and place all of the function declarations in the file, along with the required preprocess commands (e.g. #ifndef).
  • Create warmup3.c and place a skeleton of each function in the file. It contains only the signature and, if it returns something, a single return statement that returns a value of the right type.
  • Create test_warmup3.c. Put in the #includes you need, the main function, and everything necessary to make a single function call to each function.
  • Update your repository to get the Makefile from your partner.
  • Compile with:
    $ clang test_warmup3.c warmup3.c
    
  • commit your results
Partner B:
  • Make a Makefile for this project. Commit it to the repository.
  • Identify the attributes to be varied for test cases in problems 1 and 2.
  • Identify ranges of valid inputs for each attribute.
  • Suggest a set of test cases that are "normal" cases, "border" cases, and "error" cases.

Now get together and share your results. Work together to get the skeleton to compile and run properly. Go through the test case plan. Then commit the files.

The next time you do Phase 1, Partner A will do test case design for problem 3, and Partner B will do test case design for problem 4.

Phase 2: Implementation

Partner A: Implement problem 1.
Partner B:
Use svn update to receive the starting code from Partner A.
Implement the test cases to problem 1. Don't forget to use good function decomposition techniques (make a function that does the testing).

When you have completed your part of the code, update and commit.


Discussion part 1: Look at the input ranges from the black box tests. Is there separate code to handle each case? If not, are the different ranges equivalent? Also, verify that the boundaries in the input ranges match the boundaries present in the code.


Discussion part 2: Looking at student A's code, jointly develop a set of white box tests that exercise all paths in the code. If you developed more tests than the black box tests, discuss whether that code is necessary, or whether the initial tests were insufficient.


Phase 3: Compilation and Testing

Make sure you have both updated your files. Then you can begin compiling and testing. Whoever wrote the tests for the last group edits the main file, and whoever write the functions edits the functions file.

Roadmap

When you are finished with this phase, make sure you commit your code! Now you're ready to repeat the process with other problems. For this assignment, all problems are slightly different, so there is no complex roadmap. Go through phases 1, 2, and 3 for each problem, reversing your roles each problem. The problems are designed with overlapping skills so that each student gets to practice most of the skills by the end.

Good luck!

Submit

At this point, you should have done the following:
  • Checked out your repository
  • Created a folder named hw3 in your repository and run svn add hw3
    $ svn add hw3
  • Created , added, and filled in four files: warmup3.h, warmup3.c, test_warmup3.c and Makefile inside your hw3 directory.
  • If you participated in Duet Programming, make sure you svn update your duet repository, then copy over the files into your personal repository. The cp command copies files.
    mkdir CNET-cs152-spr-16/hw3
    cp cs152-spr-16-duet-0x/hw3/* CNET-cs152-spr-16/hw3/*
    cd CNET-cs152-spr-16
    svn add hw3
    
  • $ svn add warmup3.h warmup3.c test_warmup3.c Makefile duet.txt
  • Compiled your executable manually and with the Makefile
  • Executed your code to make sure it runs properly and inspected the results.
  • $ svn commit -m "hw3 warmup complete"
Now you're ready to move on to hw3!! Remember that the homework is completed individually.