-
Memory handler
Okay, here's a custom memory handler I wrote for strings so that I won't have to make a bunch of calls to malloc. I probably won't use it, but it's good practice and might come in handy sometime. The reason I thought this was a good idea was for three reasons.
1. I can get more memory when the program starts, so if I get everything I need and handle it my way then I won't have problems with malloc failing. :)
2. Instead of having pointers to memory all over the place, I know exactly where it is because each block is one after another. I think this would be good for debugging.
3. Since I only call malloc twice when the program starts, I can get better performance by avoiding expensive malloc calls.
I'm probably an idiot for trying to do this and I know that it's not made very well, but that's why I'm posting it here. Can anyone give me ideas on what to improve, what I'm doing wrong, and if I'm just a complete loser. ;)
The header file, my_mem_handler.h
Code:
#ifndef MY_MEM_HANDLER
#define MY_MEM_HANDLER
#include <stdio.h>
#include <stdlib.h>
/* Exit status */
#define GOOD_EXIT 0
#define BAD_EXIT 1
/* Error handling */
#define ERR_NOMEM 0
#define ERR_FULL_HEAP 1
extern char *err_msg[];
/* Memory handler */
typedef struct {
char *memory; /* Memory to be referenced */
unsigned *block_sizes; /* The size of each block referenced */
unsigned blocks; /* The number of blocks referenced */
unsigned N_alloc; /* Amount of referenced memory in bytes */
unsigned N_free; /* Amount of free memory in bytes */
} HEAP;
extern HEAP heap;
/* init_heap allocates memory for the heap
and sets all heap values to their initial settings.
This indicates that no memory has been referenced.
It takes the heap size as an argument. */
int init_heap( unsigned size );
/* free_heap clears all memory allocated to the
heap. */
void free_heap( void );
/* alloc_mem references the first available chunk
of memory of the given size in the heap to mem. It
takes two arguments, the address of the pointer to
be given the reference and the desired size. */
int alloc_mem( char **mem, unsigned size );
/* free_mem returns the chunk of memory referenced
by mem to the heap and sets mem to null. */
void free_mem( char **mem );
#endif
The source file, my_mem_handler.c
Code:
#include "my_mem_handler.h"
char *err_msg[] = {
"Error, couldn't allocate memory", /* ERR_NOMEM */
"Error, not enough heap space available", /* ERR_FULL_HEAP */
};
HEAP heap;
int init_heap( unsigned size )
{
/* Reserve space for the heap and set it to 0 */
heap.memory = calloc( size, sizeof( char ) );
if( !heap.memory ) {
fputs( err_msg[ERR_NOMEM], stderr );
return BAD_EXIT;
}
/* Reserve space for the block sizes and set it to 0 */
heap.block_sizes = calloc( size, sizeof( int ) );
if( !heap.block_sizes ) {
fputs( err_msg[ERR_NOMEM], stderr );
return BAD_EXIT;
}
heap.blocks = 0;
heap.N_alloc = 0;
heap.N_free = size;
return GOOD_EXIT;
}
void free_heap( void )
{
free( heap.block_sizes );
free( heap.memory );
}
int alloc_mem( char **mem, unsigned size )
{
/* Not enough space on the heap? */
if( heap.N_free < size ) {
fputs( err_msg[ERR_FULL_HEAP], stderr );
return BAD_EXIT;
}
/* Set mem to the first free block and reset the heap sizes */
*mem = heap.memory + heap.N_alloc;
heap.block_sizes[heap.blocks++] = size;
heap.N_alloc += size;
heap.N_free -= size;
return GOOD_EXIT;
}
void free_mem( char **mem )
{
heap.blocks--;
/* Reset the sizes to remove a block */
heap.N_alloc -= heap.block_sizes[heap.blocks];
heap.N_free += heap.block_sizes[heap.blocks];
/* Clear mem */
*mem = NULL;
}
-
What would be your expected output from this -
Code:
int main()
{
char* m1, *m2, *m3,*m4;
init_heap(24);
alloc_mem(&m1,8);
strcpy(m1,"mmmm111");
printf("%s",m1);
alloc_mem(&m2,8);
strcpy(m2,"mmmm222");
alloc_mem(&m3,8);
strcpy(m3,"mmmm333");
free_mem(&m2);
alloc_mem(&m4,8);
strcpy(m4,"mmmm444");
printf("%s",m3);
return 0;
}
?
-
questions:
why not return pointer to the allocated memory as malloc() does? (makes code using your memory allocator easier to read as everyone is accustomed to the conventions of standard malloc().)
why char ** and not void **?
-
hmmm, yes, you have a bit of a logic problem, as pointed out by Enmeduranki.
>>why char ** and not void **?
because...
>>here's a custom memory handler I wrote for strings
-
Enmeduranki:
I'd expect that you wouldn't get what you wanted, explained below.
moi:
I thought about it, but picked the one I thought would be easier to write without terrible bugs.
Hammer:
It's not a logic problem, that's part of the design. You have to call each free in the opposite order that it was allocated, like a stack. I couldn't figure out any good way to use a dynamic array for the heap and still allow freeing the references in random order. The biggest problem would be fragmentation, which I could fix by shuffling the elements of the array, but then I would screw up the current references. So it was easier to do it the way I did.
-
>It's not a logic problem, that's part of the design.
Sounds just like "it's not a bug, it's a feature" ! :D (j/k)
-
Hammer, you can really be funny sometimes :D
bebop: It looks like you put some thought into it, but you should extend it to work for all types of data. You can alloc it as a char* and cast it to any type. Not trying to be critical though. Job well done:) I use one all the time, by the way. It handles blocking and non-blocking defragmentation, maintains data structures to hold info on each allocated chunk, and even lets me simulate an OS with it's derived class. MM processes are very interesting stuff to me. Look at a similar post I made on this topic, too, it may be interesting...
-
Hammer:
I'll be sure to change it if you can suggest a way to deal with the problems that would be safer than just trusting the user to not be stupid and call free_mem in the right order. ;)
Sebastiani:
I'm not quite good enough to do all of that just yet. And there's really no point in doing it for all kinds of data because the only time I really use malloc is for strings. How would you suggest I go about making one more like yours?