This is an in-class exercise. An exercise page like this one will contain a brief description but is intended to be supplemented by discussion during our meeting time. Complete the exercise to the best of your ability in the time given. Feel free to talk with other students as you work, and do not be afraid to ask questions if you get stuck. Aim to complete as much as possible during our meeting, and submit on Gradescope to check your solution. You are encouraged to work at home to complete what you do not get through today, and ask questions on Piazza or in office hours.
Reinforces concepts learned in today's meeting:
- Use pointer arithmetic to access array elements
- Use pointer arithmetic to treat regions of a larger array as "sub-arrays"
- Use pointer differences to compute indices of array elements based on their displacement from the base address
- Use pointers to access subsets of a 2D array as 1D arrays
Part 1
Pull the starter code for this exercise from the public repo by taking the following steps:
-
Log into an undergraduate cluster computer. Update the course public repo with a
git pull
command. -
Confirm that you can access the template files for today’s exercise by typing
ls exercises/ex12
– you should see files namedbsearch.c
andsudoku.c
, as well as 3 plain text input puzzle filespuzzle*.txt
. There should also be filessudokuHelpers.h
,sudokuHelpers.c
, and aMakefile
for easy compilation and updating of the sudoku code. -
Navigate to your personal repo for the course and make a directory for today’s exercise. Then copy all the files from the public class repository (in the
*/exercises/ex12/*
directory) and put it in your personal repo’s directory for today’s exercise.
Part 3
Open bsearch.c
with a text editor. To compile the code, use this command:
gcc -std=c99 -pedantic -Wall -Wextra bsearch.c -g -o bsearch
or use our alias:
gccc bsearch.c -g -o bsearch
You will need to modify bsearch.c
as follows.
First, add a declaration and definition for a function called search
.
The declaration should look like this:
int *search(int *start, int *end, int search_val);
TODO
comments indicate where to add the declaration and definition.
This function implements a binary search to find an integer value
search_val
in a region of a sorted array of int
values. The start
and
end
parameters specify a range of elements to search, where start
is a pointer to the inclusive start element, and end
is a pointer to
the exclusive end element. I.e., the pointers to the elements in the range
to be searched are greater than or equal to start
, and strictly less
than end
.
If the search is successful, the search
function should return a pointer
to the element where search_val
was located. If the search is unsuccessful,
the search
function should return NULL
.
Recall that you implemented binary search in Exercise 7.
Note that in today’s exercise, you are not required to implement the binary
search using recursion. Either recursion or iteration is fine. However,
keep in mind that for Ex 7 both of the range indices low
and high
were inclusive.
Next, after you have implemented the search
function, you should complete
the code in the main
function. You will see a block of code that looks
like this:
// example of a successful search
pos = search(arr1, arr1 + 10, 809);
assert(pos != NULL);
assert(*pos == 809);
index = // TODO: compute the index of the matching element
assert(7 == index);
Fix the code at the point of the TODO
comment so that it computes the
index of the array element that pos
points to, where pos
is the result
of a successful search. Hint: this will involve a pointer difference
computation.
Once you’ve completed the main
function, you should be able to run the
program. If the tests pass, you will see the output:
All tests pass!
To finish this part of the exercise, add additional test cases to test the
search
function. You should add at least three test cases for successful
searches and three test cases for unsuccessful searches. Make sure that
all of your tests pass.
Part 4
For the next part of this exercise, you’ll be finishing the implementation
of a sudoku checker program. The purpose of the program is to read an
input puzzle file, where 0s represent empty cells. It should then check
every row, column and cube to see if the puzzle is completely solved
already, or not. You will only need to modify the sudokuHelper.c
file,
but should take time first to read through the code in the other files
and ask if you have any questions.
There are several helper functions you need to complete, as indicated
by TODO
comments in the file. In both makeCol
and makeCube
you
need to declare the unit array that will be populated and returned in
each function. (Their declarations will be identical.) You should also
carefully read through the provided code in each method to ask if you
don’t understand how they work.
Next you’ll need to call these functions from two other helpers, again
where indicated by TODO
comments in functions checkRows
, checkCols
and checkCubes
. Once this is done correctly, you should be able to
compile everything with the Makefile and run the main program with each
puzzle file as input. The first two are not correct/complete solutions,
but puzzle3.txt
is a completely solved puzzle.
Part 5
Lastly, using the tools you learned in Ex 11 during the last class
session, modify the Makefile
, adding the -g
option to your compilation
command(s) so that you can run gdb
and valgrind
on this code. Find
a fix the memory leaks in sudokuHelpers.c
for this final task.
Remember to add and commit to your local repo copy as your work. Push
to your remote repo when finished. Also scp and submit to Gradescope
to check your solution. Use exit
to logout from your ugrad
account when finished. If you continue to work on the program after class,
make sure to keep your repo updated as well!