3
votes

So I am working on a project in C where we need to implement malloc and free (meaning, we CANNOT use any C memory management functions such as malloc() or free()). This is only a code snippet, but it includes all relevant parts.

struct block_header
{
    int size;
};

typedef struct FList_elem
{
    struct block_header * header;
    struct list_elem elem;
} FLelem;

void * manual_malloc(size_t size)
{
     freeBlock = (FLelem *) mem_sbrk(newsize);

     freeBlock->header = (struct block_header *) freeBlock;
     freeBlock->header->size = newsize;
}

When allocating a new "block" of memory, we represent it via a structure FList_elem. In order to "allocate memory" for the struct, we point it at a memory address returned by mem_sbrk (works just like sbrk()). My question is, how do we establish memory for variables like size? Initially it's address is 0x0, and so assignments or references to it cause seg faults. Does it need to be a pointer so that we can set it's address, and then the value?

3
Instead of taking it as a pointer, just include it in your struct FList_elem as an object. That way you'll have one main pointer from which you can get direct access to various attributes of the block structure. - brokenfoot

3 Answers

0
votes

Instead of your original code, which stores a pointer to block_header inside the FList_elem structure, you can just embed the whole block_header structure inside the FList_elem structure:

struct block_header
{
    int size;
};

typedef struct FList_elem
{
    /* OLD code: struct block_header * header; */

    /* Better code: block_header is embedded inside FList_elem structure */
    struct block_header header;
    struct list_elem elem;
} FLelem;

In this way, you don't need to allocate block_header separately: it's just there with the rest of FList_elem bytes.

And to set the size field (and any other attribute you may add to your block header) you can just do:

freeBlock->header.size = newsize;
0
votes

When allocating the requested size, you need to add the header elements - and the pointer to the next block (eventually - the size can be computed with pointer difference as a space optimization... if this is embedded staff they are 4 bytes per block saved).

Since I think there are some incongruences, I have reported here my interpretation (not tested) of what you are trying to do:

struct block_header
{
    int size;
};

typedef struct FList_elem
{
    struct block_header header; // removed a * here: size is in place
    struct Flist_elem *elem;    // added a * here: that's the pointer to the next block.
} FLelem;

FLelem *memory_list = 0; // added a pointer for the global list - right?

void * manual_malloc(size_t newsize)   // renamed as newsize here
{
     freeBlock = (FLelem *) mem_sbrk(newsize + sizeof(FLelem));

     freeBlock->header.size = newsize;
     freeBlock->header.elem = memory_list;
     memory_list = freeBlock;
     // inserted freeBlock at the head of memory_list;
     return (void*)(freeBlock+1); // +1 to skip the header as a return address
}

The caller of the function will have returned the space after the header.

Your manual_free() function will take as an argument this returned memory pointer, and it will need to subtract and go back a freeblock in memory in order to find the header and to release the block, and than you will need some sort of tree (bit tree) to keep of track of the holes left free... If you need to handle dynamic memory - and that's where it start being interesting.

Hope I have not done errors and that it's clear enough!

-3
votes
#include <stdlib.h>
struct st *x = malloc(sizeof *x); 

Note that:

x must be a pointer

no cast is required

include appropriate header