CMSC313, Computer Organization & Assembly Language Programming, Spring 2013

Project 5: DIY Memory Allocation

Due: Tuesday April 2, 2013, 11:59pm


Objective

The objective of this programming project is to help familiarize with the syntax of various elements of the C programming language, including: arrays, structs and pointers.


Background

There are times in programming when you might want to do your own memory allocation. This might be the case if you only need allocate fixed-size blocks of memory and for some reason you do not want to rely on the operating system's memory allocator (e.g., you want your program to run on several platforms that use different memory allocation methods).

A simple way to achieve this do-it-yourself memory allocation is to declare a "large" global array of blocks. Each time your program needs a block of memory, you use an item of the array instead of asking the operating system for a chunk of memory. You keep track of a list of free blocks in your array by linking the unused items together in a linked list.

You do not need to create a new data structure to link the free blocks together: simply reuse one of the fields of the array item as the "next" pointer. You also do not need to use real pointers to link the free blocks together, you can just use the array index of the next item in the list of free blocks. Thus, you can simply reuse any integer field as the "next pointer". When your program deallocates a block of memory, that block is added to the linked list of free blocks. The beginning of the free block list will be stored in a global variable. Initially, the list of free blocks is the entire array.

If your memory allocations needs are modest, doing your own memory allocation can be faster than making calls to library functions.


Assignment

Note: This project description deliberately avoids using C syntax. This is so you figure out how to look up the syntax of various elements of the C programming language.

For this assignment, you will work with structs that represent fractions. The struct must have fields called sign, numerator and denominator. These should be, respectively, signed char, unsigned int and unsigned int. You must use typedef and struct to define a fraction type.

Your memory allocator should use a "large" global array of fractions. This must be defined in a separate file along with another global variable for the beginning of the free block list. Both the global variables should be declared static to give them file scope and ensure that code in other files does not access these variables directly.

In the same file, you must supply four functions: init_Heap(), new_frac(), del_frac() and dump_heap().

You must also supply a header file called frac_heap.h. Any program that includes frac_heap.h should be able to use your memory allocator without any additional declarations or definitions.

You should make your declarations and definitions compatible with this sample main program: main5.c. The main program should compile with your code without any modification. You should infer the correct function prototypes of the four functions listed above from how they are used in the main program.

In addition to this sample main program, you should write several main programs that test various features of your memory allocator.


Implementation Notes


Extra Credit (10 points)

For extra credit, devise a scheme that allows the programmer to request an array of fractions. The interaction should look like this:

fraction *F ; F = new_frac_array(10) ; ... print_frac( &F[3] ) ; ... del_frac_array(F) ;

In the example above, your new_frac_array() function should allocate a contiguous block of 10 items from the global array and return a pointer to the beginning of the contiguous block. Note that F is a pointer that can be used as an array of fractions. It is not an array of pointers each pointing to a fraction. Your new_frac_array() function may have to do some searching to find such a contiguous block.

Deallocating an array of fractions requires some work, because you are only given a pointer and not the size of the array. For this scheme to work, you memory allocator must keep track of the size of the arrays you have allocated previously. In the example above, when F is deallocated, your del_frac_array() function has to figure out that F was an array of 10 fractions. To do this, you will need a separate global table to remember the sizes of the arrays allocated previously. You are allowed to devise whatever scheme suits you. You do not have to be terribly efficient (that's difficult), but you are not allowed to add additional fields to fraction and you be graded on the amount of extra memory used (less is better).


Turning in your program

Use the UNIX submit command on the GL system to turn in your project. You must submit the header file frac_heap.h, the implementation frac_heap.c and your test programs test1.c, test2.c, ...

In addition, submit a typescript file showing that your test programs compiled and ran.

You may optionally submit a README file explaining anything the graders might need to know about compiling and/or running your programs.

Your submit commands will look like:

submit cs313 proj5 frac_heap.h frac_heap.c
submit cs313 proj5 test1.c test2.c test3.c test4.c test5.c test6.c
submit cs313 proj5 typescript README



Last Modified: 22 Jul 2024 11:28:18 EDT by Richard Chang
to Spring 2013 CMSC 313 Homepage