需要建议以在C中实现malloc和free

时间:2018-10-11 23:35:56

标签: c malloc free sbrk

对于学校来说,我需要编写一个程序,该程序使用自己的malloc和free实现。我需要能够报告“堆”中的所有内存块,无论是否已分配。我觉得我已经写了很好的代码来做到这一点,但是显然没有。我运行它的前几次,报告一直在同一地址上报告。在尝试调试时,有一点表明程序甚至不允许我开始分配要用作“堆”的空间,它只会出现分段错误并退出。任何关于我要去哪里,甚至根本不清理代码的指针都将非常有帮助。

#include <unistd.h>
#include <assert.h>
#include <stdio.h>


#define WORDSIZE 8
#define ALLOCMAGIC 0xbaddecaf
#define FREEMAGIC 0xdeadbeef

typedef struct __header_t {
    size_t size;
    int magic;
} header_t;

typedef struct __node_t {
    size_t size;
    struct __node_t *next;
} node_t;

node_t *head = NULL;


// Find the free node that occurs just before the given node.
node_t *findLastFree(node_t * node) {

    // Initialize some pointers to traverse the free node linked list;
    node_t *lastFree = head;
    node_t *nextFree = lastFree->next;

    // Traverse linked list until the last node's pointer is pointed to NULL,
    // meaning the end of the list.
    while (nextFree != NULL) {

        // Check if target node is less than the next node, meaning the target node
        // is between last and next.  If so, then return last node.
        if (node < nextFree) {
            return lastFree;
        }

        lastFree = nextFree;
        nextFree = lastFree->next;
    }

    // If we have reached the end of the list and the target node is still greater
    // than the last node, return last node.
    return lastFree;
}


// If the given pointer is allocated, deallocate the space and coalesce the free
// node list.
void myFree(void *ptr) {

    // Initialize some free node pointers and assert that the given pointer is
    // the beginning of allocated space.
    node_t *lastFree;
    node_t *nextFree;
    node_t *newFree;
    header_t *block = ((header_t *) ptr) - 1;
    assert(block->magic == ALLOCMAGIC);

    // Set this block's signal to free space
    block->magic = FREEMAGIC;

    // Typecast the block into a free node and set it's size.
    size_t size = block->size + sizeof(header_t);
    newFree = (node_t *) block;
    newFree->size = size;

    // Check if node is before the first free node.  If so set the new node as
    // the new head.  If not, then handle node as it occurs after head.
    if (newFree < head) {

        nextFree = head;

        // Check if new node ends at the start of head.  If so, merge them
        // into a single free node.  Else point the new node at the previous head.
        // Either way, set new free as the new head.
        if ((newFree + newFree->size) == head) {
            newFree->next = head->next;
            newFree->size = newFree->size + head->size;
        } else {
            newFree->next = head;
        }
        head = newFree;
    } else {

        // Set the free nodes for before and after the new free node.
        lastFree = findLastFree(newFree);
        nextFree = lastFree->next;

        // Check if new node is the last node.  If so, point the previous final
        // node at the new node and point the new node at NULL.
        if (nextFree == NULL) {

            lastFree->next = newFree;
            newFree->next = NULL;
        }

        // Check if end of new node is touching next node.  If so, merge them
        // into a single free node.  Else point new free and next free.
        if ((newFree + newFree->size) == nextFree) {
            newFree->next = nextFree->next;
            newFree->size = newFree->size + nextFree->size;
        } else {
            newFree->next = nextFree;
        }

        // Check if start of new node is touching last free node.  If so, merge
        // them into a single free node.  Else point last's next to new free.
        if ((lastFree + lastFree->size) == newFree) {
            lastFree->next = newFree->next;
            lastFree->size = lastFree->size + newFree->size;
        } else {
            lastFree->next = newFree;
        }
    }
}


// Split the given free node to fit the given size.  Create a new node at the 
// remainder and rearrange the free list to accomodate.
void splitBlock(node_t *node, size_t size) {

    // Create a new pointer at the end of the requested space.
    void *newBlock = node + size;

    // Set the bits of the new space as if it were allocated then freed.
    header_t *hptr = (header_t *) newBlock;
    hptr->size = (node->size - size - sizeof(header_t));
    hptr->magic = FREEMAGIC;

    // Typecast the new space into a node pointer.  Reinsert it into the free
    // node list.
    node_t *newFree = (node_t *) newBlock;
    newFree->size = node->size - size;
    newFree->next = node->next;
    node_t *lastFree = findLastFree(newFree);
    lastFree->next = newFree;
}


// Find a free node that can fit the given size.  Split the node so no space is 
// wasted.  If no node can fit requested size, increase the heap size to accomodate.
void *findFirstFit(size_t size) {

    // Create a node pointer to traverse the free node list.
    node_t *node = head;

    // Traverse the list until the end is reached.
    while(node != NULL) {

        // Check if the node can accomodate the requested size.
        if (node->size >= size) {

            // Split the current node at the requested size and return a pointer
            // to the start of the requested space.
            splitBlock(node, size);
            return (void *) node;
        }
        node = node->next;
    }

    // No free space could fit requested size, so request more space at the end
    // of the heap.
    void *newspace = sbrk(size);
    assert(newspace >= 0);

    return newspace;
}


// Allocate a block of space for the given size and return a pointer to the start
// of the freed space.

void *myMalloc(size_t need) {

    // Round the given size up to the next word size.  Add the size of a header to
    // the amount actually needed to allocate.
    need = (need + WORDSIZE - 1) & ~(WORDSIZE - 1);
    size_t actual = need + sizeof(header_t);

    // Find a free node that can accomodate the given size.  Check it is valid.
    void *firstfit = findFirstFit(actual);
    assert(firstfit >= 0);

    // Create a header for the newly allocated space.
    header_t *hptr = (header_t *) firstfit;
    hptr->magic = ALLOCMAGIC;
    hptr->size = need;

    return (void *) (hptr + 1);
}


// Print a report on the space starting at the given pointer.  Return a pointer to
// the start of the next block of space.
void *reportAndGetNext(void *ptr) {

    void *nextptr;
    header_t *hptr = (header_t *) ptr;

    // Check if the pointer is pointing to allocated space.
    if (hptr->magic == ALLOCMAGIC) {

        // Report the characteristics of the current block.
        printf("%p is ALLOCATED starting at %p and is %zd bytes long.\n", hptr, (hptr + 1), hptr->size);

        // Set the next pointer to be returned.
        nextptr = hptr + hptr->size + sizeof(header_t);
    } else {

        // Cast the pointer as a free node.  Set the next pointer to be returned.
        node_t *free = (node_t *) ptr;
        nextptr = free + free->size;

        // Report the characteristics of the current block.
        printf("%p is FREE for %zd bytes.\n", hptr, free->size);
    }
    return nextptr;
}


// Report on all blocks of space contained within the heap space, starting at the 
// given pointer.
void report(void* startheap) {

    void *ptr = startheap;
    void *end = sbrk(0);
    int count = 50;

    printf("Current Status of Heap:\n");

    while (ptr != NULL && count > 0) {
        ptr = reportAndGetNext(ptr);
        count = count - 1;
    }

    printf("Heap Length: %zd \n", (end - startheap));

}


int main(void) {

    void *start = sbrk(4096);
    assert(start >= 0);
    head = (node_t *) start;
    head->size = 4096;
    head->next = NULL;

    printf("Allocating block 1");
    void *ptr1 = myMalloc(26);
    void *ptr2 = myMalloc(126);
    report(start);
    myFree(ptr1);
    myFree(ptr2);

    return 0;
}

1 个答案:

答案 0 :(得分:0)

我看到的第一个明显的错误是指针指针异常。 SplitBlock尝试从块的开头拆分size个字节,但是当您这样做时:

void splitBlock(node_t *node, size_t size) {
    // Create a new pointer at the end of the requested space.
    void *newBlock = node + size;

您的newBlock指针实际上是该块中的size * sizof(node_t)个字节-可能已经超出了该块的末尾。如果需要字节偏移量,则需要先将node强制转换为char *,然后再进行指针算术运算。但是,您然后可能会遇到对齐问题...