In this project you will practice working with pointers
by implementing your own version of malloc()
,
calloc()
, and free()
.
The functions malloc()
,
calloc()
, and free()
maintain a table that tracks what pieces of memory
have been allocated.
malloc()
uses the table to find an
area of memory large enough for the request
and returns a pointer to the starting address of that area,
but also updates the table.
free()
deallocates memory by removing its
entry from the table.
In this project you will write functions that will manage an area in memory, giving out and recollecting chunks of it.
Copy the the given files for this project:
cp /homes/tvandrun/Public/cs245/proj6/* .
This includes a header file specifying the function
prototypes (hmalloc.h
),
an implementation file with function stubs
(hmalloc.c
---this is the one you'll need to modify),
two driver programs for testing (driver.c
and driver2.c
),
and a makefile.
This project description will first describe the hard requirements of the functions. At the end, I give you some recommendations or hints about how to implement the functions. There is more than one way to accomplish the requirements; you do not need to follow the hints if you see another way.
Your functions should maintain a large area of memory; the memory areas allocated by your functions will be areas within this large area. Your table for book keeping must also be in this area; do not allocate a completely separate area dedicated for the table.
When a piece of memory is deallocated, it should be available to be allocated again. That is, your code should be "smart" enough to tell when a previously used piece of memory is a candidate for allocation.
initializeAllocator()
Any program using your functions must call this first.
This sets up the large area of memory by calling the standard
malloc()
from stdlib.h
.
This should be the only call to the standard malloc()
in your code.
You may also want to make initial set up for the table or other
book-keeping information.
hmmalloc()
Given a certain number of bytes, return
a pointer to an available area within the big area of
the specified size,
and update the table accordingly.
If the request cannot be fulfilled (either there is not
enough memory period or there is no single block big enough),
then a message like "heap exhausted" should be displayed
on the screen and the program should exit
(exit(-1)
).
hmcalloc()
This works just like the standard calloc()
except
that it calls hmmalloc()
.
This should initialize the allocated memory to 0.
printTable()
This is purely for debugging purposes.
You will not be graded on it.
The reason I included it in hmalloc.h
is
so you can call it from the driver programs or from other tests.
You my write it as you see fit, but the intention
is to display the current state of the table.
free()
Given a starting address of an allocated chunk, mark it as available by removing its entry from the table. If the given value is not found in the table, then a message like "attempt to free a non-existent pointer" should be displayed and the program should exit.
Here is a menagerie of details about how I did my implementation.
hmalloc.c
:
one for the beginning address of the entire area,
one for the size of the table, and one for the size of the entire area.
hmmalloc
had three cases:
First, the table could be empty, so we could allocate the chunk
bytes
away from the end of the entire area;
second, we could find a space between two already-allocated
chunks big enough for the request (I searched forward
through the table which was backwards through the area
in this case);
third, the available space wasn't found between any already-allocated
chunks, but we can find a place between the last chunk and the table.
int*
or a void*
or whatever
else---pointer arithmetic depends on it.
The amount of code you need to write for this isn't very big. But it will take a lot of thinking. You'll probably spend most of your time in debugging, which will involve a lot of pain and seg faults.
driver2.c
is less complicated than driver.c
so use it first.
I also recommend you write your own, simpler test cases as you go along.
driver.c
makes a tree, then trims it down (to
exercise deallocation), and then makes it grow further.
The correct output is below.
I know it's hard to read, but if your program finishes without crashing
and does not have obviously wrong output, the chances
are good that you've got it.
(100 : (16 : (2 : (0 : *)(0 : *))(3 : (0 : *)(0 : *)(0 : *))(4 : (0 : *)(0 : *)(0 : *)(0 : *))(5 : (0 : *)(0 : *)(0 : *)(0 : *)(0 : *)))(17 : (2 : (0 : *)(0 : *))(3 : (0 : *)(0 : *)(0 : *))(4 : (0 : *)(0 : *)(0 : *)(0 : *))(5 : (0 : *)(0 : *)(0 : *)(0 : *)(0 : *))(6 : *))(18 : *)(19 : (3 : (0 : *)(0 : *)(0 : *)))) (100 : (16 : (2 : (0 : *)(0 : *))(1 : *)(4 : (0 : *)(0 : *)(0 : *)(0 : *))(1 : *))(1 : *)(18 : *)(1 : *)) (100 : (16 : (2 : (0 : (1 : *))(0 : (1 : *)))(1 : (1 : *))(4 : (0 : (1 : *))(0 : (1 : *))(0 : (1 : *))(0 : (1 : *)))(1 : (1 : *)))(1 : (1 : *))(18 : (10 : *))(1 : (1 : *)))
Turn in a hard copy of your code (hmallo.c
)
and the results of running driver.c
and driver2.c
DUE: Thursday, Nov 11, at 5:00 pm