feat: update structure

This commit is contained in:
2024-01-22 14:27:40 +08:00
parent 7836c9185c
commit 3544a28a2e
559 changed files with 120846 additions and 4102 deletions

View File

@@ -0,0 +1,19 @@
.PHONY: run
bitmap: bitmap.c testmap.c
gcc $^ -o $@
run-bitmap: bitmap
./bitmap
mymalloc: mymalloc.c testmalloc.c bitmap.c
gcc $^ -o $@
run-mymalloc: mymalloc
./mymalloc
harness: harness.c mymalloc.c bitmap.c
gcc $^ -o $@
run-harness: harness
./harness

BIN
cs2106/labs/lab4/bitmap/bitmap Executable file

Binary file not shown.

View File

@@ -0,0 +1,115 @@
#include "bitmap.h"
#include <stdio.h>
// IMPLEMENTED FOR YOU
// Utility function to print out an array of char as bits
// Print the entire bitmap. Arguments: The bitmap itself, and the length of the
// bitmap Each bit of the bitmap represents 1 byte of memory. 0 = free, 1 =
// allocated. map: The bitmap itself, an array of unsigned char.
// Each bit of the bitmap represents one byte of memory
// len: The length of the bitmap array in characters
//
// Returns: Nothing
void print_map(unsigned char *map, int len) {
int i, j;
for (i = 0; i < len; i++) {
unsigned char mask = 0b10000000;
for (j = 0; j < 8; j++) {
if (map[i] & mask)
printf("1");
else
printf("0");
mask = mask >> 1;
}
printf(" ");
}
printf("\n");
}
// Search the bitmap for the required number of zeroes (representing
// free bytes of memory). Returns index of first stretch of 0s
// that meet the criteria. You can use this as an index into
// an array of char that represents the process heap
// bitmap = Bitmap declared as an array of unsigned char
// len = Length of bitmap in characters
// num_zeroes = Length of string of 0's required
// Returns: Index to stretch of 0's of required length, -1 if no such stretch
// can be found
long search_map(unsigned char *bitmap, int len, long num_zeroes) {
int count = 0;
for (int i = 0; i < len; i++) {
unsigned char mask = 0b10000000;
for (int j = 0; j < 8; j++) {
if ((bitmap[i] & mask) == 0) {
count++;
if (count == num_zeroes) {
return i * 8 + j - num_zeroes + 1;
}
} else {
count = 0;
}
mask >>= 1;
}
}
return -1;
} // main
// Set map bits to 0 or 1 depending on whether value is non-zero
// map = Bitmap, declared as an array of unsigned char
// start = Starting index to mark as 1 or 0
// length = Number of bits to mark
// value = Value to mark the bits as. value = 0 marks the bits
// as 0, non-zero marks the bits as 1
// Returns: Nothing
// start: 7
// length: 4
// value: 1
void set_map(unsigned char *map, long start, long length, int value) {
// printf("set_map with start=%ld, length=%ld val=%d\n", start, length,
// value);
int starting_index = start / 8;
for (int i = 0; i < length; i++) {
int currIdx = (start + i) / 8;
int currOffset = (start + i) % 8;
int mask = 0b10000000;
if (value == 0) {
map[currIdx] &= ~(mask >> currOffset);
} else {
map[currIdx] |= (mask >> currOffset);
}
}
// the ~(1<< offset) is a nice trick to create, for example
// ~(1 << 2) = 1111 1011
// By anding this, you can set the value to 0 for that bit
// map[char_index + length_index] &= ~(1 << length_offset);
// the (1<< offset) is a nice trick to create, for example
// (1 << 2) = 0000 0100
// likewise, set the given bit to 1
// map[char_index + length_index] |= (1 << length_offset);
}
// IMPLEMENTED FOR YOU
// Marks a stretch of bits as "1", representing allocated memory
// map = Bitmap declared as array of unsigned char
// start = Starting index to mark
// length = Number of bits to mark as "1"
void allocate_map(unsigned char *map, long start, long length) {
set_map(map, start, length, 1);
}
// IMPLEMENTED FOR YOU
// Marks a stretch of bits as "0", representing allocated memory
// map = Bitmap declared as array of unsigned char
// start = Starting index to mark
// length = Number of bits to mark as "0"
void free_map(unsigned char *map, long start, long length) {
set_map(map, start, length, 0);
}

View File

@@ -0,0 +1,40 @@
/* Bitmap management
The bitmap should be an array of unsigned char.
*/
// Used by test harness
long get_index(void *ptr);
// Utility function to print out an array of char as bits
// Print the entire bitmap. Arguments: The bitmap itself, and the length of the
// bitmap Each bit of the bitmap represents 1 byte of memory. 0 = free, 1 =
// allocated. map: The bitmap itself, an array of unsigned char.
// Each bit of the bitmap represents one byte of memory
// len: The length of the bitmap array in characters
//
// Returns: Nothing
void print_map(unsigned char *map, int len);
// Search the bitmap for the required number of zeroes (representing
// free bytes of memory). Returns index of first stretch of 0s
// that meet the criteria. You can use this as an index into
// an array of char that represents the process heap
// bitmap = Bitmap declared as an array of unsigned char
// len = Length of bitmap in characters
// num_zeroes = Length of string of 0's required
// Returns: Index to stretch of 0's of required length
long search_map(unsigned char *bitmap, int len, long num_zeroes);
// Marks a stretch of bits as "1", representing allocated memory
// map = Bitmap declared as array of unsigned char
// start = Starting index to mark
// length = Number of bits to mark as "1"
void allocate_map(unsigned char *map, long start, long length);
// Marks a stretch of bits as "0", representing allocated memory
// map = Bitmap declared as array of unsigned char
// start = Starting index to mark
// length = Number of bits to mark as "0"
void free_map(unsigned char *, long, long);

BIN
cs2106/labs/lab4/bitmap/harness Executable file

Binary file not shown.

View File

@@ -0,0 +1,52 @@
#include <stdio.h>
#include <assert.h>
#include "mymalloc.h"
void *runmalloc(size_t len, long expected_ndx) {
long ndx;
void *ptr;
printf("Allocate %ld bytes.\n", len);
printf("Before: ");
print_memlist();
ptr = mymalloc(len);
printf("After: ");
print_memlist();
ndx = get_index((void *) ptr);
printf("\n");
assert(ndx == expected_ndx);
return ptr;
}
void runfree(void *ptr) {
printf("Free\n");
printf("Before: ");
print_memlist();
myfree(ptr);
printf("After: ");
print_memlist();
printf("\n");
}
int main() {
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
ptr1 = runmalloc(4, 0);
ptr2 = runmalloc(32, 4);
ptr3 = runmalloc(2, 36);
runfree(ptr2);
ptr2 = runmalloc(12, 4);
ptr4 = runmalloc(24, 38);
ptr5 = runmalloc(18, 16);
runfree(ptr1);
ptr1 = runmalloc(2, 0);
runfree(ptr1);
runfree(ptr2);
runfree(ptr3);
runfree(ptr4);
runfree(ptr5);
}

View File

@@ -0,0 +1,239 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "llist.h"
//#define DEBUG // Enable debug printing
// Debug printer
void dbprintf(char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
#endif
}
// Implements a double linked list.
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data) {
TNode *node = malloc(sizeof(TNode));
node->key = key;
node->pdata = data;
node->prev = NULL;
node->next = NULL;
return node;
}
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir) {
if(*llist == NULL) {
*llist = node;
(*llist)->trav = *llist;
(*llist)->tail = *llist;
}
else
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
node->next = *llist;
(*llist)->prev = node;
*llist = node;
(*llist)->trav = *llist;
}
else
{
TNode *trav = *llist;
if(dir == 0)
while(trav->next != NULL && trav->key < node->key)
trav = trav->next;
else if(dir == 1)
while(trav->next != NULL && trav->key > node->key)
trav = trav->next;
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
(trav->key > node->key && dir == 1))) {
trav->next = node;
node->prev = trav;
// Set the tail
(*llist)->tail = node;
} else {
// Insert into the previous space
node->next = trav;
if(trav->prev != NULL) {
trav->prev->next = node;
node->prev = trav->prev;
}
if(trav->next != NULL) {
}
trav->prev = node;
}
}
}
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node) {
if(*llist == NULL || node == NULL)
return;
if((*llist)->key == node->key) {
// Node to be deleted is at the front of the list.
*llist = (*llist)->next;
// Ensure that we don't point to it anymore.
if(*llist != NULL)
(*llist)->prev = NULL;
}
else
{
TNode *trav = *llist;
while(trav != NULL && trav->key != node->key)
trav = trav->next;
// We've found the deletion point
if(trav != NULL) {
trav->prev->next = trav->next;
if(trav->next != NULL)
trav->next->prev = trav->prev;
else
(*llist)->tail = trav->prev;
}
}
free(node);
}
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key) {
if(llist == NULL)
return NULL;
TNode *trav = llist;
while(trav != NULL && trav->key != key)
trav = trav->next;
return trav;
}
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir) {
if(dir == 0) {
if(node->prev == NULL)
return;
delete_node(&llist, node);
}
else
if(dir == 1) {
if(node->next == NULL)
return;
delete_node(&llist, node->next);
}
}
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *)) {
TNode *trav = llist;
while(trav) {
func(trav);
trav = trav->next;
}
}
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist) {
TNode *trav = *llist, *tmp;
while(trav) {
tmp = trav->next;
free(trav);
trav = tmp;
}
*llist = NULL;
}
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where)
{
if(llist == NULL)
return;
if(where == FRONT)
llist->trav = llist;
else
if(where == REAR)
llist->trav = llist->tail;
}
// Get the next node
TNode *succ(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->next;
return ret;
}
// Get the previous node
TNode *pred(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->prev;
return ret;
}

View File

@@ -0,0 +1,113 @@
// Uncomment the next line to enable debug printing
#define DEBUG // Enable debug printing
// The debug printer; used like a normal printf, except
// that printing can be turned off by commenting out the
// #define DEBUG above.
void dbprintf(char *format, ...);
// You should modify this structure to hold
// whatever you need to implement your
// memory manager
typedef struct td {
size_t len;
} TData;
/* -----------------------------------------
BASIC ROUTINES
Basic linked list routines
---------------------------------------- */
// Basic double linked list node.
typedef struct tn {
unsigned int key;
TData *pdata; // Pointer to the data you want to store
struct tn *trav; // Only used in the root for traversal
struct tn *tail; // Only used in the root for finding the end of the list
struct tn *prev;
struct tn *next;
} TNode;
// Insert Direction
#define ASCENDING 0
#define DESCENDING 1
// Merge direction
#define PRECEDING 0
#define SUCCEEDING 1
// Traverser position
#define FRONT 0
#define REAR 1
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data);
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir);
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node);
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key);
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir);
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist);
/* -----------------------------------------
TRAVERSAL ROUTINES
Lets you traverse the linked list
---------------------------------------- */
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *));
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where);
// Get the next node
TNode *succ(TNode *llist);
// Get the previous node
TNode *pred(TNode *llist);

BIN
cs2106/labs/lab4/bitmap/mymalloc Executable file

Binary file not shown.

View File

@@ -0,0 +1,40 @@
#include "mymalloc.h"
#include "bitmap.h"
#include <stdio.h>
#include <stdlib.h>
char _heap[MEMSIZE] = {0};
unsigned char _bitmap[BITMAP_SIZE] = {};
char lens[MEMSIZE] = {0};
// Do not change this. Used by the test harness.
// You may however use this function in your code if necessary.
long get_index(void *ptr) {
if (ptr == NULL)
return -1;
else
return (long)((char *)ptr - &_heap[0]);
}
void print_memlist() { print_map(_bitmap, BITMAP_SIZE); }
// Allocates size bytes of memory and returns a pointer
// to the first byte.
void *mymalloc(size_t size) {
long start = search_map(_bitmap, BITMAP_SIZE, size);
if (start == -1)
return NULL;
allocate_map(_bitmap, start, size);
lens[start] = size;
return (void *)(&_heap[start]);
}
// Frees memory pointer to by ptr.
void myfree(void *ptr) {
if (ptr == NULL)
return;
long ptrIdx = get_index(ptr);
long size = lens[ptrIdx];
free_map(_bitmap, ptrIdx, size);
lens[ptrIdx] = 0;
}

View File

@@ -0,0 +1,12 @@
#include "stdio.h"
#define MEMSIZE 64 // Size of memory in bytes
#define BITMAP_SIZE 8 // Size of Bitmap
// Used by the test harness
long get_index(void *ptr);
// Debugging routine
void print_memlist();
void *mymalloc(size_t);
void myfree(void *);

View File

@@ -0,0 +1,35 @@
#include "mymalloc.h"
#include <stdio.h>
void testalloc(long size, char *ptrname, char **ptr) {
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
*ptr = mymalloc(size);
if (*ptr == NULL)
printf("Allocation failed.\n");
print_memlist();
}
void testfree(char *ptr, char *ptrname) {
printf("\nFreeing %s\n", ptrname);
myfree(ptr);
print_memlist();
}
int main() {
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
testalloc(4, "ptr1", &ptr1);
testalloc(32, "ptr2", &ptr2);
testalloc(4, "ptr3", &ptr3);
testfree(ptr2, "ptr2");
testalloc(24, "ptr2", &ptr2);
testalloc(6, "ptr4", &ptr4);
testfree(ptr2, "ptr2");
testalloc(32, "ptr5", &ptr5);
testfree(ptr1, "ptr1");
testfree(ptr2, "ptr2");
testfree(ptr3, "ptr3");
testfree(ptr4, "ptr4");
testfree(ptr5, "ptr5");
}

View File

@@ -0,0 +1,54 @@
#include <stdio.h>
#include <assert.h>
#include "bitmap.h"
#define LEN 5
void print_result(unsigned char *map, int len, long length, long expected) {
long ndx = search_map(map, len, length);
printf("Length: %ld, Expected: %ld, Actual: %ld\n", length, expected, ndx);
// This will cause a crash if the index returned does not match what is expected
assert(ndx == expected);
}
int main() {
unsigned char map[LEN] = {0b11001000, 0b00011111, 0b00001100, 0b11000000, 0b00000001};
int ndx;
printf("\n");
print_result(map, LEN, 2, 2);
print_result(map, LEN, 4, 5);
print_result(map, LEN, 6, 5);
print_result(map, LEN, 12, 26);
print_result(map, LEN, 128, -1);
// Allocate map
printf("\nAllocating 2 bytes\n");
printf("BEFORE: ");
print_map(map, LEN);
ndx = search_map(map, LEN, 2);
allocate_map(map, ndx, 2);
printf("AFTER: ");
print_map(map, LEN);
printf("\n");
printf("Allocating 12 bytes\n");
printf("BEFORE: ");
print_map(map, LEN);
ndx = search_map(map, LEN, 12);
allocate_map(map, ndx, 12);
printf("AFTER: ");
print_map(map, LEN);
printf("\n");
print_result(map, LEN, 12, -1);
printf("Freeing 12 bytes\n");
printf("BEFORE: ");
print_map(map, LEN);
free_map(map, ndx, 12);
printf("AFTER: ");
print_map(map, LEN);
printf("\n");
print_result(map, LEN, 12, 26);
}

View File

@@ -0,0 +1,13 @@
.PHONY: run test
run: harness-bf
./harness-bf
test: testmalloc
./testmalloc
harness-bf: harness-bf.c llist.c mymalloc.c
gcc $^ -o $@
testmalloc: testmalloc.c mymalloc.c llist.c
gcc $^ -o $@

View File

@@ -0,0 +1,55 @@
#include <stdio.h>
#include <assert.h>
#include "mymalloc.h"
void *runmalloc(size_t len, long expected_ndx) {
long ndx;
void *ptr;
printf("Allocate %ld bytes.\n", len);
printf("Before: ");
print_memlist();
printf("\n");
ptr = mymalloc(len);
ndx = get_index((void *) ptr);
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
printf("After: ");
print_memlist();
printf("\n");
assert(ndx == expected_ndx);
return ptr;
}
void runfree(void *ptr) {
printf("Free\n");
printf("Before: ");
print_memlist();
printf("\n");
myfree(ptr);
printf("After: ");
print_memlist();
printf("\n");
}
int main() {
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
ptr1 = runmalloc(4, 0);
ptr2 = runmalloc(32, 4);
ptr3 = runmalloc(2, 36);
runfree(ptr2);
ptr2 = runmalloc(12, 4);
ptr4 = runmalloc(24, 38);
ptr5 = runmalloc(18, 16);
runfree(ptr1);
ptr1 = runmalloc(2, 34);
runfree(ptr1);
runfree(ptr2);
runfree(ptr3);
runfree(ptr4);
runfree(ptr5);
}

View File

@@ -0,0 +1,239 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "llist.h"
//#define DEBUG // Enable debug printing
// Debug printer
void dbprintf(char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
#endif
}
// Implements a double linked list.
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data) {
TNode *node = malloc(sizeof(TNode));
node->key = key;
node->pdata = data;
node->prev = NULL;
node->next = NULL;
return node;
}
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir) {
if(*llist == NULL) {
*llist = node;
(*llist)->trav = *llist;
(*llist)->tail = *llist;
}
else
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
node->next = *llist;
(*llist)->prev = node;
*llist = node;
(*llist)->trav = *llist;
}
else
{
TNode *trav = *llist;
if(dir == 0)
while(trav->next != NULL && trav->key < node->key)
trav = trav->next;
else if(dir == 1)
while(trav->next != NULL && trav->key > node->key)
trav = trav->next;
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
(trav->key > node->key && dir == 1))) {
trav->next = node;
node->prev = trav;
// Set the tail
(*llist)->tail = node;
} else {
// Insert into the previous space
node->next = trav;
if(trav->prev != NULL) {
trav->prev->next = node;
node->prev = trav->prev;
}
if(trav->next != NULL) {
}
trav->prev = node;
}
}
}
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node) {
if(*llist == NULL || node == NULL)
return;
if((*llist)->key == node->key) {
// Node to be deleted is at the front of the list.
*llist = (*llist)->next;
// Ensure that we don't point to it anymore.
if(*llist != NULL)
(*llist)->prev = NULL;
}
else
{
TNode *trav = *llist;
while(trav != NULL && trav->key != node->key)
trav = trav->next;
// We've found the deletion point
if(trav != NULL) {
trav->prev->next = trav->next;
if(trav->next != NULL)
trav->next->prev = trav->prev;
else
(*llist)->tail = trav->prev;
}
}
free(node);
}
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key) {
if(llist == NULL)
return NULL;
TNode *trav = llist;
while(trav != NULL && trav->key != key)
trav = trav->next;
return trav;
}
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir) {
if(dir == 0) {
if(node->prev == NULL)
return;
delete_node(&llist, node);
}
else
if(dir == 1) {
if(node->next == NULL)
return;
delete_node(&llist, node->next);
}
}
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *)) {
TNode *trav = llist;
while(trav) {
func(trav);
trav = trav->next;
}
}
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist) {
TNode *trav = *llist, *tmp;
while(trav) {
tmp = trav->next;
free(trav);
trav = tmp;
}
*llist = NULL;
}
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where)
{
if(llist == NULL)
return;
if(where == FRONT)
llist->trav = llist;
else
if(where == REAR)
llist->trav = llist->tail;
}
// Get the next node
TNode *succ(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->next;
return ret;
}
// Get the previous node
TNode *pred(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->prev;
return ret;
}

View File

@@ -0,0 +1,115 @@
#include <stdbool.h>
#include <stdio.h>
// Uncomment the next line to enable debug printing
#define DEBUG // Enable debug printing
// The debug printer; used like a normal printf, except
// that printing can be turned off by commenting out the
// #define DEBUG above.
void dbprintf(char *format, ...);
// You should modify this structure to hold
// whatever you need to implement your
// memory manager. You can delete the
// val field. It is only used for testlist.c
typedef struct td {
bool occupied;
size_t size;
} TData;
/* -----------------------------------------
BASIC ROUTINES
Basic linked list routines
---------------------------------------- */
// Basic double linked list node.
typedef struct tn {
unsigned int key;
TData *pdata; // Pointer to the data you want to store
struct tn *trav; // Only used in the root for traversal
struct tn *tail; // Only used in the root for finding the end of the list
struct tn *prev;
struct tn *next;
} TNode;
// Insert Direction
#define ASCENDING 0
#define DESCENDING 1
// Merge direction
#define PRECEDING 0
#define SUCCEEDING 1
// Traverser position
#define FRONT 0
#define REAR 1
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data);
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir);
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node);
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key);
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir);
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist);
/* -----------------------------------------
TRAVERSAL ROUTINES
Lets you traverse the linked list
---------------------------------------- */
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *));
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where);
// Get the next node
TNode *succ(TNode *llist);
// Get the previous node
TNode *pred(TNode *llist);

View File

@@ -0,0 +1,103 @@
#include "mymalloc.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/_types/_null.h>
#include "llist.h"
char _heap[MEMSIZE] = {0};
TNode *_memlist = NULL; // To maintain information about length
// Do not change this. Used by the test harness.
// You may however use this function in your code if necessary.
long get_index(void *ptr) {
if (ptr == NULL)
return -1;
else
return (long)((char *)ptr - &_heap[0]);
}
// Allocates size bytes of memory and returns a pointer
// to the first byte.
void *mymalloc(size_t size) {
if (_memlist == NULL) {
TData *data = malloc(sizeof(TData));
data->occupied = false;
data->size = MEMSIZE;
_memlist = make_node(0, data);
}
// loop through the list to find a free block
// if found, split the block and return the pointer
// if not found, return NULL
TNode *curr = _memlist;
TNode *best = NULL;
while (curr != NULL) {
if (curr->pdata->occupied == true) {
curr = curr->next;
continue;
}
if (curr->pdata->size < size) {
curr = curr->next;
continue;
}
if (best == NULL) {
best = curr;
curr = curr->next;
continue;
}
if (best->pdata->size > curr->pdata->size) {
best = curr;
curr = curr->next;
continue;
}
curr = curr->next;
}
if (best == NULL)
return NULL;
best->pdata->occupied = true;
if (best->pdata->size > size) {
// Create a new node with the leftover space
TData *newData = malloc(sizeof(TData));
newData->occupied = false;
newData->size = best->pdata->size - size;
TNode *newNode = make_node(best->key + size, newData);
// insert new node after the current one in the list.
insert_node(&_memlist, newNode, 0);
// change the size of the current node.
best->pdata->size = size;
}
return &_heap[best->key];
}
// Frees memory pointer to by ptr.
void myfree(void *ptr) {
if (ptr == NULL)
return;
long index = get_index(ptr);
TNode *node = find_node(_memlist, index);
if (node == NULL)
return;
node->pdata->occupied = false;
// merge with the next node if it is free
while (node->next != NULL && node->next->pdata->occupied == false) {
node->pdata->size += node->next->pdata->size;
merge_node(_memlist, node, 1);
}
while (node->prev != NULL && node->prev->pdata->occupied == false) {
TNode *prev = node->prev;
prev->pdata->size += node->pdata->size;
merge_node(_memlist, node, 0);
}
}
void print_node(TNode *node) {
printf("Status: %s Start index: %d Length: %zu\n",
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
node->pdata->size);
}
void print_memlist() { process_list(_memlist, print_node); }

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
#define MEMSIZE 64 * 1024 // Size of memory in bytes
long get_index(void *ptr);
void print_memlist();
void *mymalloc(size_t);
void myfree(void *);

Binary file not shown.

View File

@@ -0,0 +1,36 @@
#include <stdio.h>
#include "mymalloc.h"
void testalloc(long size, char *ptrname, char **ptr) {
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
*ptr = mymalloc(size);
if(*ptr == NULL)
printf("Allocation failed.\n");
print_memlist();
}
void testfree(char *ptr, char *ptrname) {
printf("\nFreeing %s\n", ptrname);
myfree(ptr);
print_memlist();
}
int main() {
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
testalloc(2048, "ptr1", &ptr1);
testalloc(6144, "ptr2", &ptr2);
testalloc(1024, "ptr3", &ptr3);
testfree(ptr2, "ptr2");
testalloc(2048, "ptr2", &ptr2);
testalloc(4096, "ptr4", &ptr4);
testfree(ptr2, "ptr2");
testalloc(3072, "ptr5", &ptr5);
testfree(ptr1, "ptr1");
testfree(ptr2, "ptr2");
testfree(ptr3, "ptr3");
testfree(ptr4, "ptr4");
testfree(ptr5, "ptr5");
}

View File

@@ -0,0 +1,14 @@
.PHONY: run test
run: harness-ff
./harness-ff
test: testmalloc
./testmalloc
harness-ff: harness-ff.c llist.c mymalloc.c
gcc $^ -o $@
testmalloc: testmalloc.c mymalloc.c llist.c
gcc $^ -o $@

View File

@@ -0,0 +1,54 @@
#include "llist.h"
#include "mymalloc.h"
#include <assert.h>
#include <stdio.h>
void *runmalloc(size_t len, long expected_ndx) {
long ndx;
void *ptr;
printf("Allocate %ld bytes.\n", len);
printf("Before: ");
print_memlist();
printf("\n");
ptr = mymalloc(len);
ndx = get_index((void *)ptr);
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
printf("After: ");
print_memlist();
printf("\n");
assert(ndx == expected_ndx);
return ptr;
}
void runfree(void *ptr) {
printf("Free\n");
printf("Before: ");
print_memlist();
printf("\n");
myfree(ptr);
printf("After: ");
print_memlist();
printf("\n");
}
int main() {
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
ptr1 = runmalloc(4, 0);
ptr2 = runmalloc(32, 4);
ptr3 = runmalloc(2, 36);
runfree(ptr2);
ptr2 = runmalloc(12, 4);
ptr4 = runmalloc(24, 38);
ptr5 = runmalloc(18, 16);
runfree(ptr1);
ptr1 = runmalloc(2, 0);
runfree(ptr1);
runfree(ptr2);
runfree(ptr3);
runfree(ptr4);
runfree(ptr5);
}

View File

@@ -0,0 +1,239 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "llist.h"
//#define DEBUG // Enable debug printing
// Debug printer
void dbprintf(char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
#endif
}
// Implements a double linked list.
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data) {
TNode *node = malloc(sizeof(TNode));
node->key = key;
node->pdata = data;
node->prev = NULL;
node->next = NULL;
return node;
}
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir) {
if(*llist == NULL) {
*llist = node;
(*llist)->trav = *llist;
(*llist)->tail = *llist;
}
else
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
node->next = *llist;
(*llist)->prev = node;
*llist = node;
(*llist)->trav = *llist;
}
else
{
TNode *trav = *llist;
if(dir == 0)
while(trav->next != NULL && trav->key < node->key)
trav = trav->next;
else if(dir == 1)
while(trav->next != NULL && trav->key > node->key)
trav = trav->next;
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
(trav->key > node->key && dir == 1))) {
trav->next = node;
node->prev = trav;
// Set the tail
(*llist)->tail = node;
} else {
// Insert into the previous space
node->next = trav;
if(trav->prev != NULL) {
trav->prev->next = node;
node->prev = trav->prev;
}
if(trav->next != NULL) {
}
trav->prev = node;
}
}
}
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node) {
if(*llist == NULL || node == NULL)
return;
if((*llist)->key == node->key) {
// Node to be deleted is at the front of the list.
*llist = (*llist)->next;
// Ensure that we don't point to it anymore.
if(*llist != NULL)
(*llist)->prev = NULL;
}
else
{
TNode *trav = *llist;
while(trav != NULL && trav->key != node->key)
trav = trav->next;
// We've found the deletion point
if(trav != NULL) {
trav->prev->next = trav->next;
if(trav->next != NULL)
trav->next->prev = trav->prev;
else
(*llist)->tail = trav->prev;
}
}
free(node);
}
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key) {
if(llist == NULL)
return NULL;
TNode *trav = llist;
while(trav != NULL && trav->key != key)
trav = trav->next;
return trav;
}
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir) {
if(dir == 0) {
if(node->prev == NULL)
return;
delete_node(&llist, node);
}
else
if(dir == 1) {
if(node->next == NULL)
return;
delete_node(&llist, node->next);
}
}
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *)) {
TNode *trav = llist;
while(trav) {
func(trav);
trav = trav->next;
}
}
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist) {
TNode *trav = *llist, *tmp;
while(trav) {
tmp = trav->next;
free(trav);
trav = tmp;
}
*llist = NULL;
}
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where)
{
if(llist == NULL)
return;
if(where == FRONT)
llist->trav = llist;
else
if(where == REAR)
llist->trav = llist->tail;
}
// Get the next node
TNode *succ(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->next;
return ret;
}
// Get the previous node
TNode *pred(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->prev;
return ret;
}

View File

@@ -0,0 +1,115 @@
#include <stdbool.h>
#include <stdio.h>
// Uncomment the next line to enable debug printing
#define DEBUG // Enable debug printing
// The debug printer; used like a normal printf, except
// that printing can be turned off by commenting out the
// #define DEBUG above.
void dbprintf(char *format, ...);
// You should modify this structure to hold
// whatever you need to implement your
// memory manager. You can delete the
// val field. It is only used for testlist.c
typedef struct td {
bool occupied;
size_t size;
} TData;
/* -----------------------------------------
BASIC ROUTINES
Basic linked list routines
---------------------------------------- */
// Basic double linked list node.
typedef struct tn {
unsigned int key;
TData *pdata; // Pointer to the data you want to store
struct tn *trav; // Only used in the root for traversal
struct tn *tail; // Only used in the root for finding the end of the list
struct tn *prev;
struct tn *next;
} TNode;
// Insert Direction
#define ASCENDING 0
#define DESCENDING 1
// Merge direction
#define PRECEDING 0
#define SUCCEEDING 1
// Traverser position
#define FRONT 0
#define REAR 1
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data);
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir);
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node);
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key);
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir);
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist);
/* -----------------------------------------
TRAVERSAL ROUTINES
Lets you traverse the linked list
---------------------------------------- */
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *));
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where);
// Get the next node
TNode *succ(TNode *llist);
// Get the previous node
TNode *pred(TNode *llist);

View File

@@ -0,0 +1,87 @@
#include "mymalloc.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/_types/_null.h>
#include "llist.h"
char _heap[MEMSIZE] = {0};
TNode *_memlist = NULL; // To maintain information about length
// Do not change this. Used by the test harness.
// You may however use this function in your code if necessary.
long get_index(void *ptr) {
if (ptr == NULL)
return -1;
else
return (long)((char *)ptr - &_heap[0]);
}
// Allocates size bytes of memory and returns a pointer
// to the first byte.
void *mymalloc(size_t size) {
if (_memlist == NULL) {
TData *data = malloc(sizeof(TData));
data->occupied = false;
data->size = MEMSIZE;
_memlist = make_node(0, data);
}
// loop through the list to find a free block
// if found, split the block and return the pointer
// if not found, return NULL
TNode *curr = _memlist;
while (curr != NULL) {
TData *data = curr->pdata;
if (data->occupied == false && data->size >= size) {
data->occupied = true;
if (data->size > size) {
// Create a new node with the leftover space
TData *newData = malloc(sizeof(TData));
newData->occupied = false;
newData->size = data->size - size;
TNode *newNode = make_node(curr->key + size, newData);
// insert new node after the current one in the list.
insert_node(&_memlist, newNode, 0);
// change the size of the current node.
data->size = size;
}
return &_heap[curr->key];
}
curr = curr->next;
}
return NULL;
}
// Frees memory pointer to by ptr.
void myfree(void *ptr) {
if (ptr == NULL)
return;
long index = get_index(ptr);
TNode *node = find_node(_memlist, index);
if (node == NULL)
return;
node->pdata->occupied = false;
// merge with the next node if it is free
while (node->next != NULL && node->next->pdata->occupied == false) {
node->pdata->size += node->next->pdata->size;
merge_node(_memlist, node, 1);
}
while (node->prev != NULL && node->prev->pdata->occupied == false) {
TNode *prev = node->prev;
prev->pdata->size += node->pdata->size;
merge_node(_memlist, node, 0);
}
}
void print_node(TNode *node) {
printf("Status: %s Start index: %d Length: %zu\n",
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
node->pdata->size);
}
void print_memlist() { process_list(_memlist, print_node); }

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
#define MEMSIZE 64 * 1024 // Size of memory in bytes
long get_index(void *ptr);
void print_memlist();
void *mymalloc(size_t);
void myfree(void *);

Binary file not shown.

View File

@@ -0,0 +1,35 @@
#include "mymalloc.h"
#include <stdio.h>
void testalloc(long size, char *ptrname, char **ptr) {
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
*ptr = mymalloc(size);
if (*ptr == NULL)
printf("Allocation failed.\n");
print_memlist();
}
void testfree(char *ptr, char *ptrname) {
printf("\nFreeing %s\n", ptrname);
myfree(ptr);
print_memlist();
}
int main() {
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
testalloc(2048, "ptr1", &ptr1);
testalloc(6144, "ptr2", &ptr2);
testalloc(1024, "ptr3", &ptr3);
testfree(ptr2, "ptr2");
testalloc(2048, "ptr2", &ptr2);
testalloc(4096, "ptr4", &ptr4);
testfree(ptr2, "ptr2");
testalloc(3072, "ptr5", &ptr5);
testfree(ptr1, "ptr1");
testfree(ptr2, "ptr2");
testfree(ptr3, "ptr3");
testfree(ptr4, "ptr4");
testfree(ptr5, "ptr5");
}

View File

@@ -0,0 +1,239 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "llist.h"
//#define DEBUG // Enable debug printing
// Debug printer
void dbprintf(char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
#endif
}
// Implements a double linked list.
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data) {
TNode *node = malloc(sizeof(TNode));
node->key = key;
node->pdata = data;
node->prev = NULL;
node->next = NULL;
return node;
}
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir) {
if(*llist == NULL) {
*llist = node;
(*llist)->trav = *llist;
(*llist)->tail = *llist;
}
else
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
node->next = *llist;
(*llist)->prev = node;
*llist = node;
(*llist)->trav = *llist;
}
else
{
TNode *trav = *llist;
if(dir == 0)
while(trav->next != NULL && trav->key < node->key)
trav = trav->next;
else if(dir == 1)
while(trav->next != NULL && trav->key > node->key)
trav = trav->next;
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
(trav->key > node->key && dir == 1))) {
trav->next = node;
node->prev = trav;
// Set the tail
(*llist)->tail = node;
} else {
// Insert into the previous space
node->next = trav;
if(trav->prev != NULL) {
trav->prev->next = node;
node->prev = trav->prev;
}
if(trav->next != NULL) {
}
trav->prev = node;
}
}
}
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node) {
if(*llist == NULL || node == NULL)
return;
if((*llist)->key == node->key) {
// Node to be deleted is at the front of the list.
*llist = (*llist)->next;
// Ensure that we don't point to it anymore.
if(*llist != NULL)
(*llist)->prev = NULL;
}
else
{
TNode *trav = *llist;
while(trav != NULL && trav->key != node->key)
trav = trav->next;
// We've found the deletion point
if(trav != NULL) {
trav->prev->next = trav->next;
if(trav->next != NULL)
trav->next->prev = trav->prev;
else
(*llist)->tail = trav->prev;
}
}
free(node);
}
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key) {
if(llist == NULL)
return NULL;
TNode *trav = llist;
while(trav != NULL && trav->key != key)
trav = trav->next;
return trav;
}
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir) {
if(dir == 0) {
if(node->prev == NULL)
return;
delete_node(&llist, node);
}
else
if(dir == 1) {
if(node->next == NULL)
return;
delete_node(&llist, node->next);
}
}
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *)) {
TNode *trav = llist;
while(trav) {
func(trav);
trav = trav->next;
}
}
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist) {
TNode *trav = *llist, *tmp;
while(trav) {
tmp = trav->next;
free(trav);
trav = tmp;
}
*llist = NULL;
}
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where)
{
if(llist == NULL)
return;
if(where == FRONT)
llist->trav = llist;
else
if(where == REAR)
llist->trav = llist->tail;
}
// Get the next node
TNode *succ(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->next;
return ret;
}
// Get the previous node
TNode *pred(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->prev;
return ret;
}

View File

@@ -0,0 +1,114 @@
// Uncomment the next line to enable debug printing
#define DEBUG // Enable debug printing
// The debug printer; used like a normal printf, except
// that printing can be turned off by commenting out the
// #define DEBUG above.
void dbprintf(char *format, ...);
// You should modify this structure to hold
// whatever you need to implement your
// memory manager. You can delete the
// val field. It is only used for testlist.c
typedef struct td {
int val;
} TData;
/* -----------------------------------------
BASIC ROUTINES
Basic linked list routines
---------------------------------------- */
// Basic double linked list node.
typedef struct tn {
unsigned int key;
TData *pdata; // Pointer to the data you want to store
struct tn *trav; // Only used in the root for traversal
struct tn *tail; // Only used in the root for finding the end of the list
struct tn *prev;
struct tn *next;
} TNode;
// Insert Direction
#define ASCENDING 0
#define DESCENDING 1
// Merge direction
#define PRECEDING 0
#define SUCCEEDING 1
// Traverser position
#define FRONT 0
#define REAR 1
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data);
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir);
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node);
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key);
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir);
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist);
/* -----------------------------------------
TRAVERSAL ROUTINES
Lets you traverse the linked list
---------------------------------------- */
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *));
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where);
// Get the next node
TNode *succ(TNode *llist);
// Get the previous node
TNode *pred(TNode *llist);

View File

@@ -0,0 +1,25 @@
#include <stdio.h>
#include <stdlib.h>
#include "mymalloc.h"
char _heap[MEMSIZE] = {0};
TNode *_memlist = NULL; // To maintain information about length
// Do not change this. Used by the test harness.
// You may however use this function in your code if necessary.
long get_index(void *ptr) {
if(ptr == NULL)
return -1;
else
return (long) ((char *) ptr - &_heap[0]);
}
// Allocates size bytes of memory and returns a pointer
// to the first byte.
void *mymalloc(size_t size) {
}
// Frees memory pointer to by ptr.
void myfree(void *ptr) {
}

View File

@@ -0,0 +1,5 @@
#define MEMSIZE 64 * 1024 // Size of memory in bytes
long get_index(void *ptr);
void *mymalloc(size_t);
void myfree(void *);

View File

@@ -0,0 +1,192 @@
#include "bintree.h"
#include "mymalloc.h"
#include <stdio.h>
#include <stdlib.h>
/* ------------------------- DO NOT IMPLEMENT THESE ----------------------
These are provided "free" to you, and you do not need to implement them,
though you MAY need to understand what they do. Some give you hints
on how to work with pointers to pointers. You MAY find some of these
functions useful.
------------------------------------------------------------------------- */
// Searches for the node containing "name" in the tree whose root is at "root",
// returning both the node ifself in "node", and its parent in "prevnode"
// (useful for deleting node). Both "node" and "prevnode" are set to NULL
// if name is not found in the tree.
void findNode(char *name, TTreeNode *root, TTreeNode **node,
TTreeNode **prevnode) {
TTreeNode *trav = root;
TTreeNode *prev = NULL;
while (trav != NULL) {
int cmp = strcmp(trav->name, name);
if (cmp == 0) {
*node = trav;
*prevnode = prev;
return;
}
prev = trav;
if (cmp < 0)
trav = trav->right;
else
trav = trav->left;
}
*node = NULL;
*prevnode = NULL;
}
// Searches for the node with the smallest value ("smallest node") in the tree
// originating at "node". Returns the smallest node and its parent in
// "smallest_node" and "parent" respectively.
void findSmallest(TTreeNode *node, TTreeNode **smallest_node,
TTreeNode **parent) {
TTreeNode *trav = node;
TTreeNode *prev = NULL;
if (trav == NULL)
return;
while (trav->left != NULL) {
prev = trav;
trav = trav->left;
}
*smallest_node = trav;
*parent = prev;
}
// Delete a node at "node" with parent node "prevnode"
void delNode(TTreeNode *node, TTreeNode *prevnode) {
// This is a leaf node
if (node->left == NULL && node->right == NULL) {
// See whether node is on parent's left or right, and NULL the
// corresponding pointer
int cmp = strcmp(prevnode->name, node->name);
// Previous node is smaller than this one. This
// node is on the right
if (cmp < 0)
prevnode->right = NULL;
else
prevnode->left = NULL;
freenode(node);
return;
}
// This has a child on the left only
if (node->right == NULL) {
// Copy the right child over
node = node->left;
freenode(node->left);
return;
}
// This has a child on the right only
if (node->left == NULL) {
node = node->right;
freenode(node->right);
return;
}
// This has children on both nodes
TTreeNode *smallest, *smallest_parent;
findSmallest(node->right, &smallest, &smallest_parent);
node = smallest;
smallest_parent->left = NULL;
freenode(smallest);
}
/* ---------------------------- IMPLEMENT THESE --------------------------- */
// Create a new node with name set to "name" and
// phoneNum set to "phoneNum".
void delTree(TTreeNode *root) {
// Implement deleting the entire tree, whose
// root is at "root".
if (root == NULL)
return;
if (root->left != NULL)
delTree(root->left);
if (root->right != NULL)
delTree(root->right);
freenode(root);
}
TTreeNode *makeNewNode(char *name, char *phoneNum) {
TTreeNode *node = mymalloc(sizeof(TTreeNode));
node->name = mymalloc(strlen(name) + 1);
strcpy(node->name, name);
strcpy(node->phoneNum, phoneNum);
node->left = NULL;
node->right = NULL;
return node;
// Implement makeNewNode to create a new
// TTreeNode containing name and phoneNum
}
// Add a new node to the tree.
// Note that "root" is a POINTER to the tree's root,
// not the root itself.
void addNode(TTreeNode **root, TTreeNode *node) {
if (*root == NULL) {
*root = node;
}
TTreeNode **trav = root;
while (1) {
int cmp = strcmp((*trav)->name, node->name);
if (cmp == 0)
return;
if (cmp > 0) {
if ((*trav)->left == NULL)
(*trav)->left = node;
else {
trav = &((*trav)->left);
continue;
}
} else if (cmp < 0) {
if ((*trav)->right == NULL)
(*trav)->right = node;
else {
trav = &((*trav)->right);
continue;
}
}
}
// Add a new node to the tree, where root is
// the POINTER to the tree's root.
}
void freenode(TTreeNode *node) {
myfree(node->name);
myfree(node);
// Frees the memory used by node.
}
void print_inorder(TTreeNode *node) {
// Implement in-order printing of the tree
// Recursion is probably best here.
if (node == NULL)
return;
if (node->left != NULL)
print_inorder(node->left);
printf("Name is %s Number is %s\n", node->name, node->phoneNum);
if (node->right != NULL)
print_inorder(node->right);
}

View File

@@ -0,0 +1,17 @@
#include <string.h>
#include <stdlib.h>
typedef struct tn {
char *name;
char phoneNum[9];
struct tn *left, *right;
} TTreeNode;
void findNode(char *, TTreeNode *, TTreeNode **, TTreeNode **);
void findSmallest(TTreeNode *, TTreeNode **, TTreeNode **);
void delNode(TTreeNode *, TTreeNode *);
void delTree(TTreeNode *);
TTreeNode *makeNewNode(char *, char *);
void addNode(TTreeNode **, TTreeNode *);
void freenode(TTreeNode *);
void print_inorder(TTreeNode *);

View File

@@ -0,0 +1,239 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "llist.h"
//#define DEBUG // Enable debug printing
// Debug printer
void dbprintf(char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
#endif
}
// Implements a double linked list.
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data) {
TNode *node = malloc(sizeof(TNode));
node->key = key;
node->pdata = data;
node->prev = NULL;
node->next = NULL;
return node;
}
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir) {
if(*llist == NULL) {
*llist = node;
(*llist)->trav = *llist;
(*llist)->tail = *llist;
}
else
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
node->next = *llist;
(*llist)->prev = node;
*llist = node;
(*llist)->trav = *llist;
}
else
{
TNode *trav = *llist;
if(dir == 0)
while(trav->next != NULL && trav->key < node->key)
trav = trav->next;
else if(dir == 1)
while(trav->next != NULL && trav->key > node->key)
trav = trav->next;
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
(trav->key > node->key && dir == 1))) {
trav->next = node;
node->prev = trav;
// Set the tail
(*llist)->tail = node;
} else {
// Insert into the previous space
node->next = trav;
if(trav->prev != NULL) {
trav->prev->next = node;
node->prev = trav->prev;
}
if(trav->next != NULL) {
}
trav->prev = node;
}
}
}
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node) {
if(*llist == NULL || node == NULL)
return;
if((*llist)->key == node->key) {
// Node to be deleted is at the front of the list.
*llist = (*llist)->next;
// Ensure that we don't point to it anymore.
if(*llist != NULL)
(*llist)->prev = NULL;
}
else
{
TNode *trav = *llist;
while(trav != NULL && trav->key != node->key)
trav = trav->next;
// We've found the deletion point
if(trav != NULL) {
trav->prev->next = trav->next;
if(trav->next != NULL)
trav->next->prev = trav->prev;
else
(*llist)->tail = trav->prev;
}
}
free(node);
}
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key) {
if(llist == NULL)
return NULL;
TNode *trav = llist;
while(trav != NULL && trav->key != key)
trav = trav->next;
return trav;
}
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir) {
if(dir == 0) {
if(node->prev == NULL)
return;
delete_node(&llist, node);
}
else
if(dir == 1) {
if(node->next == NULL)
return;
delete_node(&llist, node->next);
}
}
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *)) {
TNode *trav = llist;
while(trav) {
func(trav);
trav = trav->next;
}
}
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist) {
TNode *trav = *llist, *tmp;
while(trav) {
tmp = trav->next;
free(trav);
trav = tmp;
}
*llist = NULL;
}
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where)
{
if(llist == NULL)
return;
if(where == FRONT)
llist->trav = llist;
else
if(where == REAR)
llist->trav = llist->tail;
}
// Get the next node
TNode *succ(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->next;
return ret;
}
// Get the previous node
TNode *pred(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->prev;
return ret;
}

View File

@@ -0,0 +1,115 @@
#include <stdbool.h>
#include <stdio.h>
// Uncomment the next line to enable debug printing
#define DEBUG // Enable debug printing
// The debug printer; used like a normal printf, except
// that printing can be turned off by commenting out the
// #define DEBUG above.
void dbprintf(char *format, ...);
// You should modify this structure to hold
// whatever you need to implement your
// memory manager. You can delete the
// val field. It is only used for testlist.c
typedef struct td {
bool occupied;
size_t size;
} TData;
/* -----------------------------------------
BASIC ROUTINES
Basic linked list routines
---------------------------------------- */
// Basic double linked list node.
typedef struct tn {
unsigned int key;
TData *pdata; // Pointer to the data you want to store
struct tn *trav; // Only used in the root for traversal
struct tn *tail; // Only used in the root for finding the end of the list
struct tn *prev;
struct tn *next;
} TNode;
// Insert Direction
#define ASCENDING 0
#define DESCENDING 1
// Merge direction
#define PRECEDING 0
#define SUCCEEDING 1
// Traverser position
#define FRONT 0
#define REAR 1
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data);
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir);
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node);
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key);
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir);
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist);
/* -----------------------------------------
TRAVERSAL ROUTINES
Lets you traverse the linked list
---------------------------------------- */
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *));
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where);
// Get the next node
TNode *succ(TNode *llist);
// Get the previous node
TNode *pred(TNode *llist);

View File

@@ -0,0 +1,103 @@
#include "mymalloc.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/_types/_null.h>
#include "llist.h"
char _heap[MEMSIZE] = {0};
TNode *_memlist = NULL; // To maintain information about length
// Do not change this. Used by the test harness.
// You may however use this function in your code if necessary.
long get_index(void *ptr) {
if (ptr == NULL)
return -1;
else
return (long)((char *)ptr - &_heap[0]);
}
// Allocates size bytes of memory and returns a pointer
// to the first byte.
void *mymalloc(size_t size) {
if (_memlist == NULL) {
TData *data = malloc(sizeof(TData));
data->occupied = false;
data->size = MEMSIZE;
_memlist = make_node(0, data);
}
// loop through the list to find a free block
// if found, split the block and return the pointer
// if not found, return NULL
TNode *curr = _memlist;
TNode *best = NULL;
while (curr != NULL) {
if (curr->pdata->occupied == true) {
curr = curr->next;
continue;
}
if (curr->pdata->size < size) {
curr = curr->next;
continue;
}
if (best == NULL) {
best = curr;
curr = curr->next;
continue;
}
if (best->pdata->size > curr->pdata->size) {
best = curr;
curr = curr->next;
continue;
}
curr = curr->next;
}
if (best == NULL)
return NULL;
best->pdata->occupied = true;
if (best->pdata->size > size) {
// Create a new node with the leftover space
TData *newData = malloc(sizeof(TData));
newData->occupied = false;
newData->size = best->pdata->size - size;
TNode *newNode = make_node(best->key + size, newData);
// insert new node after the current one in the list.
insert_node(&_memlist, newNode, 0);
// change the size of the current node.
best->pdata->size = size;
}
return &_heap[best->key];
}
// Frees memory pointer to by ptr.
void myfree(void *ptr) {
if (ptr == NULL)
return;
long index = get_index(ptr);
TNode *node = find_node(_memlist, index);
if (node == NULL)
return;
node->pdata->occupied = false;
// merge with the next node if it is free
while (node->next != NULL && node->next->pdata->occupied == false) {
node->pdata->size += node->next->pdata->size;
merge_node(_memlist, node, 1);
}
while (node->prev != NULL && node->prev->pdata->occupied == false) {
TNode *prev = node->prev;
prev->pdata->size += node->pdata->size;
merge_node(_memlist, node, 0);
}
}
void print_node(TNode *node) {
printf("Status: %s Start index: %d Length: %zu\n",
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
node->pdata->size);
}
void print_memlist() { process_list(_memlist, print_node); }

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
#define MEMSIZE 64 * 1024 // Size of memory in bytes
long get_index(void *ptr);
void print_memlist();
void *mymalloc(size_t);
void myfree(void *);

View File

@@ -0,0 +1,51 @@
#include <stdio.h>
#include "phonebook.h"
#include "bintree.h"
static TTreeNode *_root = NULL;
char *findPerson(char *name)
{
TTreeNode *node, *prev;
findNode(name, _root, &node, &prev);
if (node != NULL)
return node->phoneNum;
else
return NULL;
}
void print_phonebook()
{
print_inorder(_root);
}
void addPerson(char *name, char *phoneNum)
{
if (findPerson(name) == NULL)
{
TTreeNode *node = makeNewNode(name, phoneNum);
addNode(&_root, node);
}
else
printf("%s is already in phonebook.\n", name);
}
void delPerson(char *name)
{
TTreeNode *node, *prevnode;
findNode(name, _root, &node, &prevnode);
if (node == NULL)
{
printf("Unable to find %s\n", name);
return;
}
delNode(node, prevnode);
}
void delPhonebook()
{
delTree(_root);
_root = NULL;
}

View File

@@ -0,0 +1,5 @@
char *findPerson(char *);
void addPerson(char *, char *);
void delPerson(char *);
void print_phonebook();
void delPhonebook();

View File

@@ -0,0 +1,60 @@
#include <stdio.h>
#include "phonebook.h"
#define ITEMS 5
typedef struct d
{
char *name, *tel;
} TData;
void printResult(char *name)
{
char *result;
printf("Looking for %s ", name);
result = findPerson(name);
if (result == NULL)
printf("NOT FOUND\n");
else
printf(" Number is %s\n", result);
}
int main()
{
TData data[ITEMS] = {{"Fred Astaire", "95551234"}, {"Jean Valjean", "95558764"}, {"Gal Gadot", "95551123"}, {"Aiken Dueet", "95558876"}, {"Victor Hugo", "95524601"}};
int i;
for (i = 0; i < ITEMS; i++)
{
printf("Adding %s, phone number %s\n", data[i].name, data[i].tel);
addPerson(data[i].name, data[i].tel);
}
printf("\nNow retrieiving stored data.\n");
char *result;
for (i = 0; i < ITEMS; i++)
{
printResult(data[i].name);
}
printf("\nRetrieving unknown person.\n");
printResult("Wee Tu Loh");
printf("\nPrinting entire phonebook.\n");
print_phonebook();
printf("\nDeleting Aiken Dueet.\n");
delPerson("Aiken Dueet");
print_phonebook();
printf("\nDeleting Victor Hugo.\n");
delPerson("Victor Hugo");
print_phonebook();
printf("\nDeleting entire phone book.\n");
delPhonebook();
print_phonebook();
}

View File

@@ -0,0 +1,178 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "llist.h"
#define COUNT 10
void print_node(TNode *node) {
if(node != NULL)
printf("Key: %d\n", node->key);
else
printf("Unable to find key.\n");
}
void free_data(TNode *node) {
free(node->pdata);
}
void trav_list(TNode *llist) {
reset_traverser(llist, FRONT);
TNode *node;
do {
node = succ(llist);
if(node)
print_node(node);
} while(node != NULL);
}
void rev_trav_list(TNode *llist) {
reset_traverser(llist, REAR);
TNode *node;
do{
node = pred(llist);
if(node)
print_node(node);
} while(node != NULL);
}
int main(){
TNode *llist = NULL;
int test_array[COUNT] = {10, 6, 2, 8, 1, 4, 5, 3, 9, 7};
// Insert
char c;
printf("Hit enter to start ascending order test\n");
scanf("%c", &c);
int i;
printf("Inserting in ascending order\n");
TData *data;
TNode *node;
for(i=0; i<COUNT; i++) {
data = (TData *) malloc(sizeof(TData));
data->val = test_array[i];
node = make_node(test_array[i], data);
insert_node(&llist, node, ASCENDING);
}
printf("Printing entire list\n");
process_list(llist, print_node);
printf("\n");
printf("Printing entire list using reverse traversal\n");
rev_trav_list(llist);
printf("\n");
printf("Searching for 2\n");
node = find_node(llist, 2);
print_node(node);
printf("Deleting node 2\n");
delete_node(&llist, node);
printf("Searching for 2\n");
node = find_node(llist, 2);
print_node(node);
printf("\n");
printf("Searching for 5\n");
node = find_node(llist, 5);
print_node(node);
printf("Deleting node 5\n");
delete_node(&llist, node);
printf("Searching for 5\n");
node = find_node(llist, 5);
print_node(node);
printf("\n");
printf("Searching for 22\n");
node = find_node(llist, 22);
print_node(node);
printf("Deleting node 22\n");
delete_node(&llist, node);
printf("Searching for 22\n");
node = find_node(llist, 22);
print_node(node);
printf("\n");
printf("Purging list\n");
process_list(llist, free_data);
purge_list(&llist);
printf("Printing entire list\n");
process_list(llist, print_node);
printf("\n");
printf("Hit enter to start descending order test\n");
scanf("%c", &c);
printf("Inserting in descending order\n");
for(i=0; i<COUNT; i++) {
TNode *node = make_node(test_array[i], NULL);
insert_node(&llist, node, DESCENDING);
}
printf("Printing entire list\n");
process_list(llist, print_node);
printf("\n");
printf("Printing entire list using reverse traversal\n");
rev_trav_list(llist);
printf("\n");
printf("Searching for 2\n");
node = find_node(llist, 2);
print_node(node);
printf("Deleting node 2\n");
delete_node(&llist, node);
printf("Searching for 2\n");
node = find_node(llist, 2);
print_node(node);
printf("\n");
printf("Searching for 5\n");
node = find_node(llist, 5);
print_node(node);
printf("Deleting node 5\n");
delete_node(&llist, node);
printf("Searching for 5\n");
node = find_node(llist, 5);
print_node(node);
printf("\n");
printf("Searching for 22\n");
node = find_node(llist, 22);
print_node(node);
printf("Deleting node 22\n");
delete_node(&llist, node);
printf("Searching for 22\n");
node = find_node(llist, 22);
print_node(node);
printf("\n");
printf("Purging list\n");
process_list(llist, free_data);
purge_list(&llist);
printf("Printing entire list\n");
process_list(llist, print_node);
printf("\n");
}

View File

@@ -0,0 +1,36 @@
#include <stdio.h>
#include "mymalloc.h"
void testalloc(long size, char *ptrname, char **ptr) {
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
*ptr = mymalloc(size);
if(*ptr == NULL)
printf("Allocation failed.\n");
print_memlist();
}
void testfree(char *ptr, char *ptrname) {
printf("\nFreeing %s\n", ptrname);
myfree(ptr);
print_memlist();
}
int main() {
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
testalloc(2048, "ptr1", &ptr1);
testalloc(6144, "ptr2", &ptr2);
testalloc(1024, "ptr3", &ptr3);
testfree(ptr2, "ptr2");
testalloc(2048, "ptr2", &ptr2);
testalloc(4096, "ptr4", &ptr4);
testfree(ptr2, "ptr2");
testalloc(3072, "ptr5", &ptr5);
testfree(ptr1, "ptr1");
testfree(ptr2, "ptr2");
testfree(ptr3, "ptr3");
testfree(ptr4, "ptr4");
testfree(ptr5, "ptr5");
}

View File

@@ -0,0 +1,13 @@
.PHONY: run test
run: harness-wf
./harness-wf
test: testmalloc
./testmalloc
harness-wf: harness-wf.c llist.c mymalloc.c
gcc $^ -o $@
testmalloc: testmalloc.c mymalloc.c llist.c
gcc $^ -o $@

View File

@@ -0,0 +1,55 @@
#include <stdio.h>
#include <assert.h>
#include "mymalloc.h"
void *runmalloc(size_t len, long expected_ndx) {
long ndx;
void *ptr;
printf("Allocate %ld bytes.\n", len);
printf("Before: ");
print_memlist();
printf("\n");
ptr = mymalloc(len);
ndx = get_index((void *) ptr);
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
printf("After: ");
print_memlist();
printf("\n");
assert(ndx == expected_ndx);
return ptr;
}
void runfree(void *ptr) {
printf("Free\n");
printf("Before: ");
print_memlist();
printf("\n");
myfree(ptr);
printf("After: ");
print_memlist();
printf("\n");
}
int main() {
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
ptr1 = runmalloc(4, 0);
ptr2 = runmalloc(32, 4);
ptr3 = runmalloc(2, 36);
runfree(ptr2);
ptr2 = runmalloc(12, 38);
ptr4 = runmalloc(24, 50);
ptr5 = runmalloc(18, 74);
runfree(ptr1);
ptr1 = runmalloc(2, 92);
runfree(ptr1);
runfree(ptr2);
runfree(ptr3);
runfree(ptr4);
runfree(ptr5);
}

View File

@@ -0,0 +1,239 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "llist.h"
//#define DEBUG // Enable debug printing
// Debug printer
void dbprintf(char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
#endif
}
// Implements a double linked list.
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data) {
TNode *node = malloc(sizeof(TNode));
node->key = key;
node->pdata = data;
node->prev = NULL;
node->next = NULL;
return node;
}
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir) {
if(*llist == NULL) {
*llist = node;
(*llist)->trav = *llist;
(*llist)->tail = *llist;
}
else
if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) {
node->next = *llist;
(*llist)->prev = node;
*llist = node;
(*llist)->trav = *llist;
}
else
{
TNode *trav = *llist;
if(dir == 0)
while(trav->next != NULL && trav->key < node->key)
trav = trav->next;
else if(dir == 1)
while(trav->next != NULL && trav->key > node->key)
trav = trav->next;
if(trav->next == NULL && ((trav->key < node->key && dir == 0) ||
(trav->key > node->key && dir == 1))) {
trav->next = node;
node->prev = trav;
// Set the tail
(*llist)->tail = node;
} else {
// Insert into the previous space
node->next = trav;
if(trav->prev != NULL) {
trav->prev->next = node;
node->prev = trav->prev;
}
if(trav->next != NULL) {
}
trav->prev = node;
}
}
}
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node) {
if(*llist == NULL || node == NULL)
return;
if((*llist)->key == node->key) {
// Node to be deleted is at the front of the list.
*llist = (*llist)->next;
// Ensure that we don't point to it anymore.
if(*llist != NULL)
(*llist)->prev = NULL;
}
else
{
TNode *trav = *llist;
while(trav != NULL && trav->key != node->key)
trav = trav->next;
// We've found the deletion point
if(trav != NULL) {
trav->prev->next = trav->next;
if(trav->next != NULL)
trav->next->prev = trav->prev;
else
(*llist)->tail = trav->prev;
}
}
free(node);
}
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key) {
if(llist == NULL)
return NULL;
TNode *trav = llist;
while(trav != NULL && trav->key != key)
trav = trav->next;
return trav;
}
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir) {
if(dir == 0) {
if(node->prev == NULL)
return;
delete_node(&llist, node);
}
else
if(dir == 1) {
if(node->next == NULL)
return;
delete_node(&llist, node->next);
}
}
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *)) {
TNode *trav = llist;
while(trav) {
func(trav);
trav = trav->next;
}
}
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist) {
TNode *trav = *llist, *tmp;
while(trav) {
tmp = trav->next;
free(trav);
trav = tmp;
}
*llist = NULL;
}
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where)
{
if(llist == NULL)
return;
if(where == FRONT)
llist->trav = llist;
else
if(where == REAR)
llist->trav = llist->tail;
}
// Get the next node
TNode *succ(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->next;
return ret;
}
// Get the previous node
TNode *pred(TNode *llist)
{
if(llist == NULL)
return NULL;
TNode *ret = llist->trav;
if(llist->trav != NULL)
llist->trav = llist->trav->prev;
return ret;
}

View File

@@ -0,0 +1,115 @@
#include <stdbool.h>
#include <stdio.h>
// Uncomment the next line to enable debug printing
#define DEBUG // Enable debug printing
// The debug printer; used like a normal printf, except
// that printing can be turned off by commenting out the
// #define DEBUG above.
void dbprintf(char *format, ...);
// You should modify this structure to hold
// whatever you need to implement your
// memory manager. You can delete the
// val field. It is only used for testlist.c
typedef struct td {
bool occupied;
size_t size;
} TData;
/* -----------------------------------------
BASIC ROUTINES
Basic linked list routines
---------------------------------------- */
// Basic double linked list node.
typedef struct tn {
unsigned int key;
TData *pdata; // Pointer to the data you want to store
struct tn *trav; // Only used in the root for traversal
struct tn *tail; // Only used in the root for finding the end of the list
struct tn *prev;
struct tn *next;
} TNode;
// Insert Direction
#define ASCENDING 0
#define DESCENDING 1
// Merge direction
#define PRECEDING 0
#define SUCCEEDING 1
// Traverser position
#define FRONT 0
#define REAR 1
// Create a new node. You need to
// Create your own TData node, populate
// it, then create a new node with a suitable
// key. Insertion into the link list is
// by ascending order of the key. An example key
// might be the starting address of a memory segment.
TNode *make_node(unsigned int key, TData *data);
// Inserts a node into the correct point of the
// double linked list. The list is sorted
// in ascending order of the key. Duplicate keys
// are permitted, though not recommended.
// llist = Pointer to link list
// node = Pointer to node created by make_node
// dir = 0: Insert in ascending order
// dir = 1: Insert in descending order
void insert_node(TNode **llist, TNode *node, int dir);
// Remove a given node from the linked list
void delete_node(TNode **llist, TNode *node);
// Find a node that has the value of key
// If there are duplicate keys, the first one encountered
// will be returned.
TNode *find_node(TNode *llist, unsigned int key);
// Merge the node provided with either the node after or the node before.
// You need to manage merging the data in node->pdata yourself. This code just
// deletes the larger of the two nodes.
// dir = 0: Merge with node before
// dir = 1: Merge with node after
void merge_node(TNode *llist, TNode *node, int dir);
// Purge the entire list. You must
// free any dynamic data in the TData
// struct yourself.
void purge_list(TNode **llist);
/* -----------------------------------------
TRAVERSAL ROUTINES
Lets you traverse the linked list
---------------------------------------- */
// Go over every element of llist, and call func
// func prototype is void func(TNode *);
void process_list(TNode *llist, void (*func)(TNode *));
// Reset traverser
// where=0 START: Resets traverser to start of list
// where=1 END: Rsets
void reset_traverser(TNode *llist, int where);
// Get the next node
TNode *succ(TNode *llist);
// Get the previous node
TNode *pred(TNode *llist);

View File

@@ -0,0 +1,103 @@
#include "mymalloc.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/_types/_null.h>
#include "llist.h"
char _heap[MEMSIZE] = {0};
TNode *_memlist = NULL; // To maintain information about length
// Do not change this. Used by the test harness.
// You may however use this function in your code if necessary.
long get_index(void *ptr) {
if (ptr == NULL)
return -1;
else
return (long)((char *)ptr - &_heap[0]);
}
// Allocates size bytes of memory and returns a pointer
// to the first byte.
void *mymalloc(size_t size) {
if (_memlist == NULL) {
TData *data = malloc(sizeof(TData));
data->occupied = false;
data->size = MEMSIZE;
_memlist = make_node(0, data);
}
// loop through the list to find a free block
// if found, split the block and return the pointer
// if not found, return NULL
TNode *curr = _memlist;
TNode *best = NULL;
while (curr != NULL) {
if (curr->pdata->occupied == true) {
curr = curr->next;
continue;
}
if (curr->pdata->size < size) {
curr = curr->next;
continue;
}
if (best == NULL) {
best = curr;
curr = curr->next;
continue;
}
if (best->pdata->size < curr->pdata->size) {
best = curr;
curr = curr->next;
continue;
}
curr = curr->next;
}
if (best == NULL)
return NULL;
best->pdata->occupied = true;
if (best->pdata->size > size) {
// Create a new node with the leftover space
TData *newData = malloc(sizeof(TData));
newData->occupied = false;
newData->size = best->pdata->size - size;
TNode *newNode = make_node(best->key + size, newData);
// insert new node after the current one in the list.
insert_node(&_memlist, newNode, 0);
// change the size of the current node.
best->pdata->size = size;
}
return &_heap[best->key];
}
// Frees memory pointer to by ptr.
void myfree(void *ptr) {
if (ptr == NULL)
return;
long index = get_index(ptr);
TNode *node = find_node(_memlist, index);
if (node == NULL)
return;
node->pdata->occupied = false;
// merge with the next node if it is free
while (node->next != NULL && node->next->pdata->occupied == false) {
node->pdata->size += node->next->pdata->size;
merge_node(_memlist, node, 1);
}
while (node->prev != NULL && node->prev->pdata->occupied == false) {
TNode *prev = node->prev;
prev->pdata->size += node->pdata->size;
merge_node(_memlist, node, 0);
}
}
void print_node(TNode *node) {
printf("Status: %s Start index: %d Length: %zu\n",
node->pdata->occupied ? "ALLOCATED" : "FREE", node->key,
node->pdata->size);
}
void print_memlist() { process_list(_memlist, print_node); }

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
#define MEMSIZE 64 * 1024 // Size of memory in bytes
long get_index(void *ptr);
void print_memlist();
void *mymalloc(size_t);
void myfree(void *);

Binary file not shown.

View File

@@ -0,0 +1,36 @@
#include <stdio.h>
#include "mymalloc.h"
void testalloc(long size, char *ptrname, char **ptr) {
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
*ptr = mymalloc(size);
if(*ptr == NULL)
printf("Allocation failed.\n");
print_memlist();
}
void testfree(char *ptr, char *ptrname) {
printf("\nFreeing %s\n", ptrname);
myfree(ptr);
print_memlist();
}
int main() {
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
testalloc(2048, "ptr1", &ptr1);
testalloc(6144, "ptr2", &ptr2);
testalloc(1024, "ptr3", &ptr3);
testfree(ptr2, "ptr2");
testalloc(2048, "ptr2", &ptr2);
testalloc(4096, "ptr4", &ptr4);
testfree(ptr2, "ptr2");
testalloc(3072, "ptr5", &ptr5);
testfree(ptr1, "ptr1");
testfree(ptr2, "ptr2");
testfree(ptr3, "ptr3");
testfree(ptr4, "ptr4");
testfree(ptr5, "ptr5");
}