33 * [ Fixing memory problems] ( #fixing-memory-problems )
44 * [ Getting started] ( #getting-started )
55* [ The problems] ( #the-problems )
6- * [ Fixing palindromes] ( #fixing-palindromes )
7- * [ Disemvowel] ( #disemvowel )
86 * [ Mergesort] ( #mergesort )
97 * [ Array merge] ( #array-merge )
108
1311# Background
1412
1513This lab is a collection of several C programming exercises with an
16- emphasis on arrays, pointers, and memory management. The first is an
17- introduction to a tool for finding memory leaks, the second is a simple
18- exercise on 1-D arrays of characters, and the last is a more complex
19- array-of-array problem where I give you much less to begin with.
14+ emphasis on arrays, pointers, and memory management.
2015
2116For more information (including information on how to use ``` valgrind ``` ), see
22- the [ Lab3 pre-lab] ( https://wiki.umn.edu/UMMCSci/CSci3401f13/Lab3Prelab ) .
17+ the [ C programming pre-lab] ( https://github.com/UMM-CSci-Systems/C-programming-pre-lab ) .
2318
24- ## Testing and the CMockery framework
19+ ## Testing and the Google Test framework
2520
2621Each of these exercises comes with a set of tests implemented using [ the
27- CMockery testing framework for C] ( http://code.google.com/p/cmockery/ ) .
28- You won't have to learn anything about the CMockery framework, but you
29- will need to add some components to your compilation instructions to
30- include the CMockery library so the tests actually run.
31- The CMockery files in the ` lib ` directory
32- were built for 64-bit
33- Linux boxes (FC18). If you want to use these tests on a different architecture
34- you'll need to download and build the library for your gear.
35-
36- We think the tests are pretty reasonable, but make ** no** promises that
22+ Google Test framework for C] ( https://github.com/google/googletest ) , aka
23+ ` gtest ` . You won't have to learn anything about ` gtest ` , but you
24+ will need to be able to compile and run the tests that we provide.
25+
26+ We think the tests are pretty reasonable, but make * no* promises that
3727they are in any way complete. Obviously you want your code to pass at
3828least these tests, but you shouldn't assume that passing these tests
3929guarantees any kind of correctness. You're welcome to read the tests
40- and extend them if
41- you'd like. You may even need to make changes to the
30+ and extend them if you'd like. You may even need to make changes to the
4231test code to handle memory leaks
43- [ (see below)] ( https://github.com/UMM-CSci-Systems/C-Lab-Starter#fixing-memory-problems ) .
44- Do be careful to not remove or weaken the tests, though; at a minimum you definitely
45- want to be able to pass the tests as given.
46-
47- On a related note, don't over focus on the tests. CMockery frankly
48- doesn't give you super useful error messages or info when things fail.
49- You can get more information using the ``` gdb ``` debugger, but
50- that's not trivial to use. In many cases it will be as or more useful to
51- write little bits of code that print out useful information from your
52- code to help with debugging. You'll eventually want to remove all that,
53- but it may be * awfully* useful while you're exploring.
32+ [ (see "fixing memory problems" below)] ( #fixing-memory-problems ) .
33+ Do be careful to not remove or weaken the tests, though; at a minimum
34+ you definitely want to be able to pass the tests as given.
5435
5536## Fixing memory problems
5637
@@ -69,19 +50,22 @@ in the test code. If the test code calls some function `f()` that returns an
6950array or string that is allocated somewhere in ` f ` (or a function ` f ` calls),
7051then that memory is lost if the test code doesn't free up that returned array.
7152So if ` valgrind ` says there's a leak where some memory is allocated in a function
72- and then returned to the test code, then the fix is _ in the test code_ . In general
73- we _ don't_ encourage/want you to be changing the test code (you could always
74- just change the test code to say everything passes!), but if the memory leaks
75- to the test code, then that's where the fix has to be made.
53+ and then returned to the test code, then the fix is _ in the test code_ . In general
54+ we don't encourage you to fiddle with the
55+ test code (you could always just change the test code to say everything
56+ passes!), but if the memory leaks to the test code, then that's where the
57+ fix has to be made.
7658
7759## Getting started
7860
79- You should then fork this repo to get the
80- starter code.
81- There are several directories there,
82- one for each project. We would recommend doing them in the order listed
83- below; there's no overwhelming reason that you need to do them in any
84- particular order, however, and it would be far better to move on to the
61+ You should first fork this repository to get the
62+ starter code, and remember to add any collaborators right away. You should
63+ then clone the repository to whatever machine you're going to work on.
64+
65+ There are several directories here, one for each project.
66+ We would recommend doing them in the order listed below; there's no
67+ overwhelming reason that you need to do them in any particular order,
68+ however, and it would be far better to move on to the
8569next one rather than get buried in one and not make any progress.
8670
8771The basic structure for each project is (for an imaginary project
@@ -92,131 +76,107 @@ The basic structure for each project is (for an imaginary project
9276 - In every case we wrote one or more helper functions, but these
9377 don't have to be included in the ` .h ` file unless you
9478 want to include them in the tests.
95- - ` foo_test.c ` , which is the test file we wrote using
96- CMockery.
79+ - ` foo.c ` , which includes the initial stub (or an incorrect version)
80+ of the program you're working with in that part.
81+ - ` main.c ` , which gives you a "main" function that you can use to
82+ run your code separate from the test code. You don't have to ever
83+ do this, but you might find it useful in debugging.
84+ - ` foo_test.cpp ` , which is the test file we wrote using ` gtest ` . The
85+ ` .cpp ` ending is because this is actually a C++ file not a strict
86+ C file. That will affect how you compile the test code, but you
87+ won't have to know/learn anything about C++ for this lab.
88+
89+ Your job then is typically to complete or fix ` foo.c ` , which provides
90+ the implementation of the function listed in ` foo.h ` .
91+
92+ To compile the ` main ` use the following:
93+
94+ ``` bash
95+ gcc -Wall -g -o foo foo.c main.c
96+ ```
9797
98- There are also top level ` include ` and ` lib `
99- directories that contain:
98+ (where you replace ` foo ` with the appropriate name for the project
99+ you're working on). If all goes well, that should generate an executable
100+ ` foo ` that you can run with ` ./foo ` .
100101
101- - ` include/cmockery.h ` , which is the CMockery include file
102- that the test file includes.
103- - ` lib/libcmockery_la-cmockery.o ` , which is the object file
104- containing the compiled versions of all the CMockery routines.
102+ To compile the test code use the following:
105103
106- Your job then is typically to write ` foo.c ` , which provides
107- the implementation of the function listed in ` foo.h ` . To
108- compile the test code (with all the CMockery stuff) use the following:
109104``` bash
110- gcc -Wall -g -o foo_test foo.c foo_test.c ../lib/libcmockery_la-cmockery.o
111- ```
112- (where you replace ` foo ` with the appropriate name for the project you're working
113- on). The ` -g ` flag is something we haven't talked about and
114- not strictly necessary; it causes a variety of useful debugging
115- information to be included in the executable, however, which can be
116- * extremely* helpful when using tools like ` valgrind ` or the
117- ` gdb ` debugger.
105+ g++ -Wall -g -o foo_test foo.c foo_test.cpp -lgtest
106+ ```
107+
108+ _ Notice that this uses ` g++ ` instead of ` gcc ` . This because the ` gtest `
109+ is technically a C++ library, but it also works for "plain" C code, which
110+ is all we need it for here. The ` -g ` flag isn't strictly necessary; it
111+ causes a variety of useful debugging information to be included in
112+ the executable, however, which can be * extremely* helpful when using
113+ tools like ` valgrind ` or the ` gdb ` debugger. If you don't include it,
114+ for example, then those tools won't be able to report accurate or useful
115+ line numbers or function names. The ` -lgtest ` tells the compiler to include
116+ the ` gtest ` library (that's the ` -l ` part) when generating the executable.
118117
119118---
120119
121120# The problems
122121
123122:bangbang : Remember: For each problem you should at a minimum
123+
124124* Pass our tests, and
125125* Have _ no_ memory leaks, as confirmed by ` valgrind ` .
126- * Remove any print statements that you used to debug your code before you turn it in.
126+ * Remove any print statements or other code that you used to debug your code before you turn it in.
127127
128128Also, please don't lose your brains and forget good programming practices just because you're working in a new language. C can be quite difficult to read under the best of circumstances, and using miserable names like ` res ` , ` res2 ` , and ` res3 ` doesn't help. * Use functions* to break up complicated bits of logic; it's really not fun when a group turns in a solution that is one huge function, especially when there are several instances of repeated logic.
129129
130130Some things to watch our for:
131+
131132* In the past there has been strong inverse correlation between length
132133and correctness on these problem. If you find yourself wandering off into 2
133134or (especially!) 3 pages of code for any of these, you've likely lost the plot
134135and should probably ask for some help.
135136* Make sure you initialize all variables (including variables used to index arrays in loops). C won't give you an error if you fail to initialize something, and sometimes you can get lucky and your tests will accidentally pass because, at least that one time, you happened to get the "right" initial value. That doesn't mean your code is correct, though.
136137* Make sure you allocate space for the null terminator ` \0 ` when allocating space for strings.
137138
138- [ There are more comprehensive tips and suggestions here.] ( https://github.umn.edu/UMM-CSci-Systems/C-Lab-Starter/blob/master/Tips_and_suggestions.md )
139-
140- ## Fixing palindromes
141-
142- Before you start writing your own C code, we'll start by using valgrind
143- to identify memory leaks in an existing program. In the
144- ` palindrome ` directory there is a program that
145- determines (in sort of a dumb way) if a string is a palindrome. The file
146- ` palindrome.c ` has the code that checks for palindromes and (instead of
147- doing the more obvious thing of returning a boolean) returns the string
148- "Yes" or "No". The file ` palindrome_test.c ` uses the CMockery library
149- mentioned above to test that the ` palindrome ` function works. You should
150- go into that ` palindrome ` directory in your project and compile the
151- program:
152- ``` bash
153- gcc -Wall -g -o palindrome_test palindrome.c palindrome_test.c ../lib/libcmockery_la-cmockery.o
154- ```
155- Run the resulting executable and
156- verify that all six tests pass.
157-
158- Look at the code a little and see if you can spot any obvious memory
159- leaks. Then run ` valgrind ` on your executable and see what it tells you
160- about memory leaks in this code. Then go through and fix the memory
161- leaks so that ` valgrind ` is happy (and the tests still pass).
162-
163- ## Disemvowel
164-
165- "Disemvoweling" is the act of removing all the vowels (a, e, i, o, and
166- u, both upper and lowercase) from a piece of text. Your task here is to
167- write a function
168- ``` C
169- char * disemvowel (char* str);
170- ```
171- that takes a null-terminated string, and returns a new null-terminated
172- string (i.e., it doesn't mangle the original one) that contains the same
173- characters in the same order, minus all the vowels. Note that resulting
174- array of characters will need to be allocated, and will typically be
175- shorter than the input string. It would be desirable to not waste memory
176- and only allocate what you actually need for the return string; you
177- might find valgrind useful for helping check for leaks.
178-
179- We've provided a `main.c` which you can compile instead of
180- `disemvowel_test.c` if you want to try out disemvoweling different
181- strings from the command line. :bangbang: You
182- need to make sure you only compile one of `main.c` and
183- `disemvowel_test.c`, otherwise you'll get a compiler error about trying to define `main()`
184- twice.
139+ There are more comprehensive tips and suggestions in ` Tips_and_suggestions.md ` in the repository.
185140
186141## Mergesort
187142
188143Your task here is to implement a well known sorting algorithm in C,
189144e.g.,
145+
190146``` C
191147void mergesort (int size, int values[ ] );
192148```
149+
193150This is a
194- destructive sorting operation, and should alter the array that it's
195- given. Note that since C doesn't know how large arrays are, we pass in
151+ _destructive_ sorting operation, i.e., it should alter the array that it's
152+ given by rearranging the elements in that that array. Note that since C
153+ doesn't know how large arrays are, we pass in
196154the size as an argument.
197155
198156To simplify the process, we've provided you with [Java implementations of
199157Quicksort and
200158Mergesort](https://github.umn.edu/gist/mcphee/83e9818b21ef9cb3cde4) that
201159you can use as models. We strongly
202- recommend you take advantage of these both because it will help ensure
203- that you focus on the C issues on these problems and because it'll make
160+ recommend you take advantage of these; doing so will help ensure
161+ that you focus on the C issues on these problems, and it'll make
204162them easier to grade. (Having to figure out some crazy, unexpected
205163approach is much more time consuming than reading a "standard"
206164solution.)
207165
208166Common approaches to Mergesort require allocating temporary arrays; you
209167should make a point of freeing these up when they're no longer needed,
210168as you certainly wouldn't want a common operation like sorting to leak a
211- bunch of memory every time it's called. Again, valgrind should be your
169+ bunch of memory every time it's called. Again, ` valgrind` should be your
212170friend.
213171
214172## Array merge
215173
216174Your task here is to implement
175+
217176```C
218177int* array_merge(int num_arrays, int* sizes, int** values);
219178```
179+
220180Here ` values ` is an array of arrays
221181of integers, where each of the sub-arrays can have different length (so
222182it's not really a standard 2-D array). Because C doesn't know the size
@@ -232,7 +192,7 @@ information around, and how many wonderfully unpleasant errors can
232192result from doing this incorrectly. It's a ** lot** safer if arrays know
233193how big they are._
234194
235- `array_merge` should then generate a sorted list (small to large) of the
195+ ` array_merge ` should then generate a single sorted list (small to large) of the
236196unique values (i.e., no duplicates) in ` values ` . Since we haven't yet
237197learned how to return multiple values in C, we're going to use a
238198slightly cheesy hack and return the ` k ` unique values in an array of
@@ -254,11 +214,6 @@ unique values is much smaller than the number of entries in `values`;
254214your solution should make a point of freeing up any unused memory.
255215
256216You might also find your sorting algorithm from above useful in sorting
257- your results. With a little care, you can put the results in an unsorted
217+ your results. With a little care, you can put the all the unique values in an unsorted
258218array, and then ask your sorting algorithm to sort the desired bit of
259219the array without messing with that important first element.
260-
261- ---
262-
263- People that contributed to this write-up before the project was moved
264- to Github included Nic McPhee, Vincent Borchardt, and KK Lamberty.
0 commit comments