Lab 5: Managing Memory
In this lab you'll examine how your machine (and your C compiler) allocates and uses memory. You'll do this lab in PARTNERS.
Goals:
- Examine some compiled code on the Pi
- Run your program in a debugger and trace procedure calls
- Create a simple database
Part 1: Start with a couple db_entry
s.
- Create a simple program in a file
simple.c
that importsdata.h
. Here's a start:
// CSSE 132 Lab 5: simple.c // Names: <put your names here> #include "data.h" void main() { // your code here }
- Compile it (
gcc -g -o simple simple.c data.c
) - Add a rule called
simple
to the makefile to automate the compiling step. - Make sure to add this new file to SVN (
svn add simple.c
) - Open up
data.h
to see what you're including insimple.c
.
1.1 Using the stack
Once you've got it working, add code to the main function:
- Create a new instance of a
struct db_entry
calledstack
on the stack, and sets "name" and "value". (HINT: the struct is already declared in data.h, you don't have to declare it again -- just use it.) - Print the entry using
dbe_print
(see data.h to see the function's declaration). HINT: you have to pass a memory address todbe_print
, not a struct value.
1.2 Debugging your program
Use GDB to examine your program.
- Launch gdb:
gdbtui ./simple
- Set a "breakpoint" to stop at the beginning of main:
break main
- Run it:
run
- When it stops, you should see code. If you don't see code, make sure
-g
is part of your gcc command. - To advance:
- for the next line in the same function: type
next
and hit enter. - for the next line in any function (step into a function call): type
step
and hit enter.
- for the next line in the same function: type
- To get information about variables: type
info locals
and hit enter. - To examine an expression, type
print foo
(foo is the c expression, for examplestack.name
)
1.3 Using the heap
When you've got the stack-based db_entry
printing out properly, make another one using malloc.
- Create an additional
struct db_entry
calledheap
on the heap.
HINT: you may need to include "stdlib.h" if you see warnings about "implicit declaration". - Print
heap
using the same function as above. - Update the struct to set the name and value (HINT: the
->
operator is useful) - Don't forget to
free
it!
Part 2: Allocating and Freeing something more complicated
Allocating the db_entry
struct with strings set at runtime is not simple: you
have to allocate space not only for the struct, but also for the contents of
the structs! In this next stage, you'll be automating this process.
Your allocator, dbe_alloc
will:
- Allocate space for a
db_entry
struct - Allocate space for the name and value members of the struct
- Copy in the strings to the newly allocated memory
You'll also need to make a de-allocator called dbe_free
that does the reverse:
- Free the memory used by name and value members of the struct
- Free the memory used by the struct
The goal is to make it easy to create and destroy db_entry
structs. After
you create dbe_alloc
and dbe_free
, this is what constructing, printing and
freeing an entry will resemble:
struct db_entry* data = dbe_alloc("My Name", "My Value"); dbe_print(data); dbe_free(data);
Add the above three lines of code to your simple.c
program. Compile and run
your code to see what it does (you should see a segmentation fault). Why does
it fail?
(To determine why it fails, use gdb to examine the values of data after each of these lines.)
2.1 Implement dbe_alloc
and dbe_free
These functions are implemented in the file named data.c.
Open that file in an editor and finish the implementations of dbe_alloc
and `dbe_free.
When you're done, you should see your simple program print something, not
quit with a segmentation fault:
My Name => My Value
Some hints:
- Start by allocating enough space for the struct
- You can figure out how long a string is using
strlen
. See thestrlen
manual pages (manpage) for more details: typeman strlen
at the command line. - You must null-terminate the strings, so you will need to allocate one byte
more than the length of the string. The string
"hi"
has length 2, but actually has a third character that is equal to'\0'
. - You can copy a series of bytes from one location to another using
memcpy
. Again, see the manpage for details. - Read the comments in data.c... really, they should be helpful.
2.2 Testing your allocator
While running your simple
program is a good test, we've provided you with
many more unit tests. To run them, use make test
to make the test
program,
then run that program.
When dbe_alloc
and dbe_free
are complete, you'll see the first test called
test_dbe_allocAndFree
pass.
Part 3: Completing data.c
When you run the tests, you will see there's more work to do.
Take a look inside lab5.c. You can see how the database is intended to be
used. As you make progress on the rest of the lab, you can use this file to
test your progress. (You can also run the tests in test
.)
Finish the following other functions in data.c:
do_add_entry
db_remove
db_count_entries
do_list_database
db_find_one
do_remove_first_match
For information about how these are used, read the main
function in lab5.c
and also look at the comments in data.c. You should be able to gradually
uncomment the code in that file as you complete parts of this lab.
Finishing the Lab
Once you've finished implementing all the functions:
- Test that it works. Make the
test
program, and run it. - Make sure the code in lab5.c runs (whether you've edited it or not).
- Ensure both your names are on all the files you edited.
- Commit your changes to SVN.