From 97c66d55c31a93ba53aaef3c7e1521988a7f60c5 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 16:42:36 -0500 Subject: [PATCH 1/9] Paste in text from last year. This just shoves in the text from last year. There's quite a lot of cleaning that needs to be done before this is ready to go live. --- README.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/README.md b/README.md index a6d0557..755cff9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,163 @@ # C-programming-pre-lab + Pre-lab to get started on compiling and running C programs and valgrind + +- [Background](#Background) + - [Checking vs. Exploration](#Checking_vs_Exploration) + - [Compiling and running a C program](#Compiling_and_running_a_C_progra) + - [Using valgrind to find memory leaks](#Using_valgrind_to_find_memory_le) +- [Exercise](#Exercise) + +Background +---------------------------------------- + +This pre-lab is for the _C and memory management_ labs, parts 1 and 2, +which includes several C programming exercises with an emphasis on arrays, pointers, +and memory management. The Internet is chock full of C tutorials, etc.; +some are listed on the +[CSci3403 Resources Page](https://github.umn.edu/UMM-CSci3403-F15/Resources/wiki), but I'm +sure there are zillions of good resources out there I've never heard of. +There are also several examples of C that are written to deliberately +illustrate some relevant concepts in `~mcphee/pub/CSci3401/C_examples`. +I'd be happy to go over any of these in class or lab if you have +questions, so feel free to ask. + +### Checking vs. Exploration + +[As this article points out nicely](http://www.developsense.com/2009/08/testing-vs-checking.html), +it's useful to make distinction between checking (which is what we +typically call testing in our courses) and exploration (he calls it +testing, but I prefer exploration given that "testing" means other +things). Checking is what we do to see if our code (still) works. +Exploration is what we do to learn more about a domain or a tool or a +language. Exploration is often crucial when we're new to a space, and +it's important to recognize that the stuff we're writing when we explore +is often pretty crappy (because we don't know what we're doing yet). As +a result one often does the exploring off to the side, with the +intention of throwing it away. I bring all this up because I suspect +there will be a fair amount of exploring that goes on during this lab. +Try to be intentional and honest about that. Step off to the side and +try a little exploratory code to figure out if you've got an idea worked +out correctly. Then throw away that "quick and dirty" code, and bring +your new knowledge back to the project at hand. + +### Compiling and running a C program + +In the exercise below you'll need to edit, (re)compile, and run a C +program that you can find at +`~mcphee/pub/CSci3401/Lab3_prelab/check_whitespace.c`. Assuming you've +copied this to a directory in your space, you can compile this using the +command +``` {.syntaxHighlightingPlugin} +gcc -g -Wall -o check_whitespace check_whitespace.c +``` + +`gcc` is the GNU C Compiler, which is pretty much the only C compiler +people use on Linux boxes these days. The meaning of the flags: +- `-g` tells `gcc` to include debugging information in the generated + executable. This is allows, for example, programs like `valgrind` + (described below) to list line numbers where it thinks there are + problems. Without `-g` it will identify functions, but not have line + numbers. +- `-Wall` (it's a capital 'W') is short for "Warnings all" and turns + on *all* the warnings that `gcc` supports. This is a Very Good Idea + because there are a ton of crazy things that C will try to + "understand" for you, and `-Wall` tells the compiler to warn you + about those things instead of just quietly (mis) interpreting them. + You should typically use `-Wall` and make sure to figure out and + clean up any warnings you do get. +- `-o ` tells `gcc` to put the resulting executable in a file + with the given name. If you don't provide the `-o` flag then `gcc` + will write the executable to a file called `a.out` for strange + historical reasons. + +Assuming your program compiled correctly ( **check the output!**) then you +should be able to run the program like any other executable: +```{bash} +./check_whitespace +``` + +### Using valgrind to find memory leaks + +One of the more subtle problems with explicit memory management is that +you can allocate memory that you never free up again when you're done +with it. This will typically never lead to an error, but can cause a +long-running process to consume more and more memory over time until its +performance begins to degrade or it ultimately crashes the system. Since +system processes (e.g. web servers) often run for days, weeks, or months +between restarts, a memory leak in such a program can be quite serious. +As a simple example, consider the (silly) function +```{c} +void f(char *str) { + char *c = calloc(100, sizeof(char)); + /* Do stuff with c */ + return 0; + } +``` + +The problem here is the fact that `f` allocates 100 bytes (100 +characters) for `c` to point to which are never freed. This means that +every time we call `f`, 100 bytes will be allocated to this process that +we'll *never* be able to get back because we have no way of accessing +that pointer outside of `f`. To fix that problem (assuming we really +need to allocate that space) we need to free it before we return: +``` {c} +void f(char *str) { + char *c = calloc(100, sizeof(char)); + /* Do stuff with c */ + free(c); + return 0; + } +``` + +These sorts of memory leaks can actually be really nasty to spot, so +happily there's a nice program called `valgrind` that can help identify +them. If your executable is `my_prog`, then running +``` {bash} +valgrind ./my_prog +``` + +will run the program as normal, and then print out a memory usage/leak +report at the end. To get more detailed information, including what +lines generate a leak, *make sure to compile your program with the `-g` +flag* and then add the `--leak-check=full` flag: +``` {bash} +valgrind --leak-check=full ./my_prog +``` + +This generates lots of output of the form: + + ==28587== 18 bytes in 1 blocks are definitely lost in loss record 50 of 50 + ==28587== at 0x400522F: calloc (vg_replace_malloc.c:418) + ==28587== by 0x80486AE: str_reverse (palindrome.c:12) + ==28587== by 0x804870A: palindrome (palindrome.c:27) + ==28587== by 0x80487FF: not_palindrome (palindrome_test.c:13) + ==28587== by 0x8048963: test_long_strings (palindrome_test.c:54) + ==28587== by 0x804A1B8: _run_test (cmockery.c:1519) + ==28587== by 0x804A5A7: _run_tests (cmockery.c:1624) + ==28587== by 0x80489B3: main (palindrome_test.c:68) + +This tells you that 18 bytes were lost, and that were allocated by +`calloc` (the top line of the trace), which was called on line 12 of +`palindrome.c` in the function `str_reverse` (next to top line of the +trace), etc. Note that this tells you where the lost bytes were +*allocated*, which doesn't always tell you much about where they should +be *freed*, as that's going to depend on how they're used after they're +allocated. + Exercise +------------------------------------ + +Take the code we gave you for `check_whitespace.c`. Compile the program +and run `valgrind` on it to find any leaks it may have (hint: it has at +least one). Write why the memory errors happen, and fix them. Submit +your fixed code (with comments at the top indicating what errors you +found and how you fixed them) in the usual way-- by forking this repository and adding +your instructor and your TA as collaborators. Be sure to create a `prelab` subdirectory +for storing your files. + +``` +Peter Dolan - 16 Sep 2015 +KK Lamberty - 12 Sep 2012 +Nic McPhee - 12 Sep 2012 +Vincent Borchardt - 16 Aug 2012 +``` From 59ff17cd90413bb4266c00b3bce0e696027f7301 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 21:36:10 -0500 Subject: [PATCH 2/9] Perform an editing pass. I went through and made a few minor changes and necessary modifications to the way the Markdown was being handled. --- README.md | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 755cff9..fe8558f 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,10 @@ This pre-lab is for the _C and memory management_ labs, parts 1 and 2, which includes several C programming exercises with an emphasis on arrays, pointers, and memory management. The Internet is chock full of C tutorials, etc.; some are listed on the -[CSci3403 Resources Page](https://github.umn.edu/UMM-CSci3403-F15/Resources/wiki), but I'm -sure there are zillions of good resources out there I've never heard of. +[CSci3403 Resources Page](https://github.umn.edu/UMM-CSci3403-F15/Resources/wiki), but there are no doubt zillions of good resources out there we've never heard of. There are also several examples of C that are written to deliberately illustrate some relevant concepts in `~mcphee/pub/CSci3401/C_examples`. -I'd be happy to go over any of these in class or lab if you have +We'll be happy to go over any of these in class or lab if you have questions, so feel free to ask. ### Checking vs. Exploration @@ -48,12 +47,14 @@ program that you can find at `~mcphee/pub/CSci3401/Lab3_prelab/check_whitespace.c`. Assuming you've copied this to a directory in your space, you can compile this using the command -``` {.syntaxHighlightingPlugin} + +```bash gcc -g -Wall -o check_whitespace check_whitespace.c ``` `gcc` is the GNU C Compiler, which is pretty much the only C compiler people use on Linux boxes these days. The meaning of the flags: + - `-g` tells `gcc` to include debugging information in the generated executable. This is allows, for example, programs like `valgrind` (described below) to list line numbers where it thinks there are @@ -63,7 +64,7 @@ people use on Linux boxes these days. The meaning of the flags: on *all* the warnings that `gcc` supports. This is a Very Good Idea because there are a ton of crazy things that C will try to "understand" for you, and `-Wall` tells the compiler to warn you - about those things instead of just quietly (mis) interpreting them. + about those things instead of just quietly (mis)interpreting them. You should typically use `-Wall` and make sure to figure out and clean up any warnings you do get. - `-o ` tells `gcc` to put the resulting executable in a file @@ -71,23 +72,26 @@ people use on Linux boxes these days. The meaning of the flags: will write the executable to a file called `a.out` for strange historical reasons. -Assuming your program compiled correctly ( **check the output!**) then you +Assuming your program compiled correctly (**check the output!**) then you should be able to run the program like any other executable: + ```{bash} ./check_whitespace ``` -### Using valgrind to find memory leaks +### Using valgrind to find memory leaks One of the more subtle problems with explicit memory management is that you can allocate memory that you never free up again when you're done with it. This will typically never lead to an error, but can cause a long-running process to consume more and more memory over time until its performance begins to degrade or it ultimately crashes the system. Since -system processes (e.g. web servers) often run for days, weeks, or months +system processes (e.g. file servers, authentication servers, and web servers) +often run for days, weeks, or months between restarts, a memory leak in such a program can be quite serious. -As a simple example, consider the (silly) function -```{c} +As a simple example, consider the (silly) function: + +```C void f(char *str) { char *c = calloc(100, sizeof(char)); /* Do stuff with c */ @@ -101,7 +105,8 @@ every time we call `f`, 100 bytes will be allocated to this process that we'll *never* be able to get back because we have no way of accessing that pointer outside of `f`. To fix that problem (assuming we really need to allocate that space) we need to free it before we return: -``` {c} + +```C void f(char *str) { char *c = calloc(100, sizeof(char)); /* Do stuff with c */ @@ -113,15 +118,19 @@ void f(char *str) { These sorts of memory leaks can actually be really nasty to spot, so happily there's a nice program called `valgrind` that can help identify them. If your executable is `my_prog`, then running + ``` {bash} valgrind ./my_prog ``` will run the program as normal, and then print out a memory usage/leak report at the end. To get more detailed information, including what -lines generate a leak, *make sure to compile your program with the `-g` -flag* and then add the `--leak-check=full` flag: -``` {bash} +lines generate a leak, + +* Make sure to compile your program with the `-g` flag, and +* Add the `--leak-check=full` flag when running `valgrind`: + +```bash valgrind --leak-check=full ./my_prog ``` @@ -144,16 +153,16 @@ trace), etc. Note that this tells you where the lost bytes were *allocated*, which doesn't always tell you much about where they should be *freed*, as that's going to depend on how they're used after they're allocated. - Exercise + +Exercise ------------------------------------ -Take the code we gave you for `check_whitespace.c`. Compile the program +1. Take the code we gave you for `check_whitespace.c`. Compile the program and run `valgrind` on it to find any leaks it may have (hint: it has at -least one). Write why the memory errors happen, and fix them. Submit -your fixed code (with comments at the top indicating what errors you -found and how you fixed them) in the usual way-- by forking this repository and adding -your instructor and your TA as collaborators. Be sure to create a `prelab` subdirectory -for storing your files. +least one). +2. In `Leaks.md` describe why the memory errors happen, and how to fix them. +3. Actually fix the code. +4. Commit, push, etc. ``` Peter Dolan - 16 Sep 2015 From 550e30958558faebe4ad0b0be2bfe904c9941b0f Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 21:56:47 -0500 Subject: [PATCH 3/9] Create a stub for the leak report. Created a stub Markdown file for the leak report, and updated the write-up to use the new file name for the leak report. --- README.md | 2 +- leak_report.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 leak_report.md diff --git a/README.md b/README.md index fe8558f..d6d5276 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Exercise 1. Take the code we gave you for `check_whitespace.c`. Compile the program and run `valgrind` on it to find any leaks it may have (hint: it has at least one). -2. In `Leaks.md` describe why the memory errors happen, and how to fix them. +2. In `leak_report.md` describe why the memory errors happen, and how to fix them. 3. Actually fix the code. 4. Commit, push, etc. diff --git a/leak_report.md b/leak_report.md new file mode 100644 index 0000000..7c6b7ca --- /dev/null +++ b/leak_report.md @@ -0,0 +1,4 @@ +# Leak report + +_Use this document to describe whatever memory leaks you find in `clean_whitespace.c` and how you might fix them. You should also probably remove this explanatory text._ + From 9595fb113458231b940e9198a7b47ed0fb991d21 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 21:57:59 -0500 Subject: [PATCH 4/9] Copy `check_whitespace.c` into the repo. Copies the starter code into the repository instead of having it be in my home directory. This fixes #4. --- README.md | 9 ++--- check_whitespace.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 check_whitespace.c diff --git a/README.md b/README.md index d6d5276..efc33a2 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,9 @@ your new knowledge back to the project at hand. ### Compiling and running a C program -In the exercise below you'll need to edit, (re)compile, and run a C -program that you can find at -`~mcphee/pub/CSci3401/Lab3_prelab/check_whitespace.c`. Assuming you've -copied this to a directory in your space, you can compile this using the +In the exercise below you'll need to edit, (re)compile, and run the C +program `check_whitespace.c` that is provided in this repository. +Assuming you're in the project directory, you can compile this using the command ```bash @@ -157,7 +156,7 @@ allocated. Exercise ------------------------------------ -1. Take the code we gave you for `check_whitespace.c`. Compile the program +1. Compile the program `check_whitespace.c` and run `valgrind` on it to find any leaks it may have (hint: it has at least one). 2. In `leak_report.md` describe why the memory errors happen, and how to fix them. diff --git a/check_whitespace.c b/check_whitespace.c new file mode 100644 index 0000000..84afb4a --- /dev/null +++ b/check_whitespace.c @@ -0,0 +1,95 @@ +#include +#include +#include + +/* + * Strips spaces from both the front and back of a string, + * leaving any internal spaces alone. + */ +char* strip(char* str) { + int size; + int num_spaces; + int first_non_space, last_non_space, i; + char* result; + + size = strlen(str); + + // This counts the number of leading and trailing spaces + // so we can figure out how big the result array should be. + num_spaces = 0; + first_non_space = 0; + while (first_non_space=0 && str[last_non_space] == ' ') { + ++num_spaces; + --last_non_space; + } + + // If num_spaces >= size then that means that the string + // consisted of nothing but spaces, so we'll return the + // empty string. + if (num_spaces >= size) { + return ""; + } + + // Allocate a slot for all the "saved" characters + // plus one extra for the null terminator. + result = calloc(size-num_spaces+1, sizeof(char)); + // Copy in the "saved" characters. + for (i=first_non_space; i<=last_non_space; ++i) { + result[i-first_non_space] = str[i]; + } + // Place the null terminator at the end of the result string. + result[i-first_non_space] = '\0'; + + return result; +} + +/* + * Return true (1) if the given string is "clean", i.e., has + * no spaces at the front or the back of the string. + */ +int is_clean(char* str) { + char* cleaned; + int result; + + // We check if it's clean by calling strip and seeing if the + // result is the same as the original string. + cleaned = strip(str); + + // strcmp compares two strings, returning a negative value if + // the first is less than the second (in alphabetical order), + // 0 if they're equal, and a positive value if the first is + // greater than the second. + result = strcmp(str, cleaned); + + return result == 0; +} + +int main() { + int i; + int NUM_STRINGS = 7; + // Makes an array of 7 string constants for testing. + char* strings[] = { "Morris", + " stuff", + "Minnesota", + "nonsense ", + "USA", + " ", + " silliness " + }; + + for (i=0; i Date: Mon, 12 Sep 2016 22:04:19 -0500 Subject: [PATCH 5/9] Removed refer to examples in my home directory. Looking over those examples, they're scattered and have almost no documentation. I think there is probably a place for some more focused and better documented examples, but suggesting that people go rummaging around in these is almost certainly not a good idea. Consequently I just removed that bit of text. --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index efc33a2..50b91d9 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,6 @@ which includes several C programming exercises with an emphasis on arrays, point and memory management. The Internet is chock full of C tutorials, etc.; some are listed on the [CSci3403 Resources Page](https://github.umn.edu/UMM-CSci3403-F15/Resources/wiki), but there are no doubt zillions of good resources out there we've never heard of. -There are also several examples of C that are written to deliberately -illustrate some relevant concepts in `~mcphee/pub/CSci3401/C_examples`. -We'll be happy to go over any of these in class or lab if you have -questions, so feel free to ask. ### Checking vs. Exploration From 3adb73b5a0a8f4d5001aa1b006e93024f35162e8 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 22:08:48 -0500 Subject: [PATCH 6/9] Fix ToC links. None of the table of contents links worked, and I think this fixes that. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 50b91d9..59c82a2 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ Pre-lab to get started on compiling and running C programs and valgrind -- [Background](#Background) - - [Checking vs. Exploration](#Checking_vs_Exploration) - - [Compiling and running a C program](#Compiling_and_running_a_C_progra) - - [Using valgrind to find memory leaks](#Using_valgrind_to_find_memory_le) -- [Exercise](#Exercise) +- [Background](#background) + - [Checking vs. Exploration](#checking-vs-Exploration) + - [Compiling and running a C program](#compiling-and-running-a-c-progra) + - [Using valgrind to find memory leaks](#using-valgrind-to-find-memory-leaks) +- [Exercise](#exercise) Background ---------------------------------------- From 4d41d78aac50c8e5ab0af420cbf09645a0c29598 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 22:10:28 -0500 Subject: [PATCH 7/9] Fix remaining ToC links. There were two table of contents links that were still broken. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59c82a2..3fd5b78 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Pre-lab to get started on compiling and running C programs and valgrind - [Background](#background) - - [Checking vs. Exploration](#checking-vs-Exploration) - - [Compiling and running a C program](#compiling-and-running-a-c-progra) + - [Checking vs. Exploration](#checking-vs-exploration) + - [Compiling and running a C program](#compiling-and-running-a-c-program) - [Using valgrind to find memory leaks](#using-valgrind-to-find-memory-leaks) - [Exercise](#exercise) From 0393699b49c816677f5d0a26bcdd04708454cb87 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 22:16:14 -0500 Subject: [PATCH 8/9] Move the "edit history" at the bottom of the write-up to a new `Credits.md`. There was an TWiki style edit/credit history at the bottom of the write-up that didn't really feel very "Git-esque", so I moved it to a new `Credits.md` file. --- Credits.md | 3 +++ README.md | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 Credits.md diff --git a/Credits.md b/Credits.md new file mode 100644 index 0000000..bf436ca --- /dev/null +++ b/Credits.md @@ -0,0 +1,3 @@ +# Credits + +This pre-lab was initially conceived by Vincent Borchardt, KK Lamberty, and Nic McPhee, with most of the initial implementation by Vincent. Subsequent editing and updates was provided by Peter Dolan, KK Lamberty, and Nic McPhee. diff --git a/README.md b/README.md index 3fd5b78..7c910ff 100644 --- a/README.md +++ b/README.md @@ -158,10 +158,3 @@ least one). 2. In `leak_report.md` describe why the memory errors happen, and how to fix them. 3. Actually fix the code. 4. Commit, push, etc. - -``` -Peter Dolan - 16 Sep 2015 -KK Lamberty - 12 Sep 2012 -Nic McPhee - 12 Sep 2012 -Vincent Borchardt - 16 Aug 2012 -``` From 62a3c5c14a99cefbed6b319f9830c50b4faa1a60 Mon Sep 17 00:00:00 2001 From: Nic McPhee Date: Mon, 12 Sep 2016 22:24:37 -0500 Subject: [PATCH 9/9] Add dates to `Credits.md`. I forgot to include the dates when the lab was first created in `Credits.md` and this fixes that. --- Credits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Credits.md b/Credits.md index bf436ca..ad8613c 100644 --- a/Credits.md +++ b/Credits.md @@ -1,3 +1,3 @@ # Credits -This pre-lab was initially conceived by Vincent Borchardt, KK Lamberty, and Nic McPhee, with most of the initial implementation by Vincent. Subsequent editing and updates was provided by Peter Dolan, KK Lamberty, and Nic McPhee. +This pre-lab was initially conceived by Vincent Borchardt, KK Lamberty, and Nic McPhee, in August and September, 2012. Most of the initial implementation was by Vincent, with subsequent editing and updates was provided by Peter Dolan, KK Lamberty, and Nic McPhee.