I need some help with my assignment. My job is to create/implement malloc/free functions in C using “Explicit free list among only the free blocks” technique. I have already studied a lot of materials, but I am still stuck at some point and I do not understand some details. So my job is to create 4 functions – initialize(), allocate() ,free() and check(). I can use only one global variable void *memory – this is the block in which I can allocate my memory using alloc().
So I wanted to implement this using doubly linked-list and I created a structure:
typedef struct memoryBlock{
struct memoryBlock *prev,*next;
}memoryBlock;
And the structure for the header:
typedef struct header{
int size;
}header;
I was advised in my class to create a separate structure for a free memory block and another separate structure for an allocated block. My first idea was to distinguish the free/allocated blocks using one bit of the block size in header – set it to 1 if the block is allocated and 0 if it is free. ( I saw this technique used in implicit lists). So my question is: do I need to create a freeBlock and allocatedBlock structure for an explicit list or can I just use the one bit of the size?
The second question is: do I need a separate structure for the header/footer of the block? Or can I just write the size of the block in the header/footer as *(int *)ptr = size; ? I tried to use this in the initialize() function:
void initialize(void *ptr, int size){
memory = ptr;
*(int *)memory = size; //header
*((int *)memory + size) = size; //footer
}
Is this correct, please?
Many thanks for any help.
do I need to create a freeBlock and allocatedBlock structure for an explicit list[…]?
This sound to me like a very good idea. Just don't misunderstand the advice: You don't need two different structure definitions but two different lists. You can realize this with two pointers, one for free blocks and one for allocated blocks.
[…] can I just use the one bit of the size?
You can only use one bit of size if it is unused otherwise. If you choose bit 0 it will only work when only even numbers of memory words are allocated.
do I need a separate structure for the header/footer of the block?
That depends on your design and algorithm. Are you bound to create a header and a footer?
Or can I just write the size of the block in the header/footer as *(int *)ptr = size;?
You can do this. But I would assign the given pointer to a (temporary) pointer to the right struct and then assign values right in their places.
void initialize(void *ptr, int size) {
memory = ptr;
header* h = memory;
h->size = size;
}
Additional observation: Instead of
typedef struct memoryBlock{
struct memoryBlock *prev,*next;
}memoryBlock;
better get used to this, it will save you a lot of pulled-out hair:
typedef struct memoryBlock {
struct memoryBlock *prev;
struct memoryBlock *next;
} memoryBlock;
Note: Due to the (seemingly) complexity of pointer, please raise the warning level of you compiler to the maximum. Read all warnings and eliminate their reasons.
Related
I searched quite a bit and I found similar problems but I still couldn't fix my issue.
I want to allocate memory for an array of pointers to tables (each table has its own linked list)
I hope I explained the idea properly, here's the code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Meal
{
struct Meal* next;
char* productname;
int price;
int quantity;
}Meal, * PMeal;
typedef struct Table //each table is supposed to have its own linked list of meals
{
PMeal next;
PMeal prev;
int tableNumber;
int cheque;
}Table;
typedef struct allTables
{
int maxoftables;
Table** tarray;
int numberoftables;
}allTables;
This is how I'm trying to dynamically allocate the array of pointers to tables:
(I think that this part is correct, it doesn't crash)
allTables tables;
tables.tarray = (Table**)malloc(sizeof(Table*) * tables.maxoftables)
Note: tables.maxoftables is initialized before the call to malloc, it's the maximum number of tables
And this is how I'm trying to initialize the linked lists in each table:
(This is where it tells me "Access violation writing location")
for (i = 0; i < tables.maxoftables; i++)
{
(tables.tarray[i])->cheque = 0;
(tables.tarray[i])->next = NULL;
(tables.tarray[i])->prev = NULL;
(tables.tarray[i])->tableNumber = i + 1;
}
I believe I could just allocate an array of struct Table but that is not allowed.
I hope everything that is needed for you to help me is here and that it's explained properly
Thanks!
Your code sample is nearly complete. The allocation reserves proper space for N pointers, but what do they point to? The memory range from malloc() is uninitialized and could be random/leftover data. A calloc() will both allocate memory and clear the range to zeros; the result is that all your table pointers would be NULL. That also makes it easy to spot bad pointers when you encounter runtime exceptions.
If calloc() was used and later when .cheque was assigned (or other struct members), the target address when writing to memory would start with the struct pointer (NULL) plus an offset of X bytes for the struct member:
// pseudo code
(NULL + small-byte-offset) <-- 0
The first page of virtual memory can be referred to as "zero page". Within your user program, most often zero page is intentionally left unmapped and useful for debugging cases like this.
While an array of table pointers was sufficiently allocated, they don't point to any valid memory. You'd also need to allocate .maxoftables structures and reference those with your allocated pointers.
It's unfortunate that allocating a struct array is somehow disallowed since it's fast/cheap to allocate an array with one request. Instead, you'd have to resort to inefficient means like this: allocate a Table structure plus check and assign the alloc result for each element of the pointer array.
Side note when allocating with calloc() : since all your struct members will be zero, that leads to a side-benefit where only 1 struct member from your example would need to be initialized (i + 1).
For the project i need to make my own malloc/free program. But i really don't know how to start making the functions. The teacher included some what every function should do but i still don't know how to begin. We only had 1 lesson for C so i'm also not that familiar with the language. These are the 2 first function of the program.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define HEAP_SIZE 1024
#define BLOCK_SIZE 64
#define NUMBER_OF_BLOCKS ((HEAP_SIZE) / (BLOCK_SIZE))
struct block
{
uint8_t *address;
uint32_t alloc_count;
struct block *prev;
struct block *next;
};
struct list
{
struct block *first;
struct block *last;
};
/* Initializes the given list to be the empty list.
*
* Preconditions:
* - the given list is a valid pointer to an object of type struct list
*
* This function is already implemented for you.
*/
static void list_init(struct list *list)
{
list->first = NULL;
list->last = NULL;
}
/* Returns true when the given block is valid.
*
* This function is already implemented for you.
*/
static bool block_is_valid(const struct block *block)
{
}
if anyone could provide me some more tips to get me on the right path or even a answer and explain me a bit so i can do the rest f the program on my own. It would be really helpfull.
EDIT: i may have asked a too vague of a question. So here is to point what i do know:
- The uint8/32_t is a type for int that are 8/32 bits in size.
- i know what pointers, Ive done the exercises on www.learn-c.org/ since that's
the thing that we did in class and also the only thing. so i have a basic
understanding of what i learned the that site.
What I'm confused about:
- I need to make a empty list. but i'm confused since i can't use malloc unless
the teacher means i have to make a normal list. But i'm pretty sure there is
no built in list() command in C.
If you have a copy of C Programming Language (2nd Edition), chapter 5 has a simple malloc() and free() implementation.
You should have a pointer to the beginning of the free memory block, and you need to advance the pointer with each memory allocation request. Since you are given the total heap and the block sizes, you can do something like
static struct block malloc_region[NUMBER_OF_BLOCKS];
Then treat this statically allocated memory as your heap and advance the pointer as new memory allocation request is done.
I want to create a struct with 2 variables, such as
struct myStruct {
char charVar;
int intVar;
};
and I will name the structs as:
struct myStruct name1;
struct myStruct name2;
etc.
The problem is, I don't know how many variables will be entered, so there must be infinite nameX structures.
So, how can I name these structures with variables?
Thanks.
You should use an array and a pointer.
struct myStruct *p = NULL;
p = malloc(N * sizeof *p); // where N is the number of entries.
int index = 1; /* or any other number - from 0 to N-1*/
p[index].member = x;
Then you can add elements to it by using realloc if you need to add additional entries.
Redefine myStruct as
struct myStruct {
char charVar;
int intVar;
struct myStruct *next;
};
Keep track of the last structure you have as well as the start of the list. When addding new elements, append them to the end of your linked list.
/* To initialize the list */
struct myStruct *start, *end;
start = malloc(sizeof(struct myStruct));
start->next = NULL;
end = start;
/* To add a new structure at the end */
end->next = malloc(sizeof(struct myStruct));
end = end->next;
end->next = NULL;
This example does not do any error checking. Here is how you would step along the list to print all the values in it:
struct myStruct *ptr;
for(ptr = start; ptr != NULL; ptr = ptr->next)
printf("%d %s\n", ptr->intVar, ptr->charVar);
You not have to have a distinct name for each structure in a linked list (or any other kind of list, in general). You can assign any of the unnamed structures to the pointer ptr as you use them.
So, how can I name these structures with variables?
I think every beginner starts out wanting to name everything. It's not surprising -- you learn about using variables to store data, so it seems natural that you'd always use variables. The answer, however, is that you don't always use variables for storing data. Very often, you store data in structures or objects that are created dynamically. It may help to read about dynamic allocation. The idea is that when you have a new piece of data to store, you ask for a piece of memory (using a library call like malloc or calloc). You refer to that piece of memory by its address, i.e. a pointer.
There are a number of ways to keep track of all the pieces of memory that you've obtained, and each one constitutes a data structure. For example, you could keep a number of pieces of data in a contiguous block of memory -- that's an array. See Devolus's answer for an example. Or you could have lots of little pieces of memory, with each one containing the address (again, a pointer) of the next one; that's a linked list. Mad Physicist's answer is a fine example of a linked list.
Each data structure has its own advantages and disadvantages -- for example, arrays allow fast access but are slow for inserting and deleting, while linked lists are relatively slow for access but are fast for inserting and deleting. Choosing the right data structure for the job at hand is an important part of programming.
It usually takes a little while to get comfortable with pointers, but it's well worth the effort as they open up a lot of possibilities for storing and manipulating data in your program. Enjoy the ride.
I have implemented a basic queue structure in C using void pointers. The procedure is as follows:
initializing the structure - I set the size of the variable type to be stored in the queue
push - I pass the pointer to the variable to be stored, the queue then grabs a copy for itself
front - the structure returns a void* to the element in front. I may just grab the pointer, or memcpy() it to have a local copy.
The struct itself looks like this:
struct queue
{
void* start; //pointer to the beginning of queue
void* end; //-||- to the end
size_t memsize; //size of allocated memory, in bytes
size_t varsize; //size of a single variable, in bytes
void* initial_pointer; //position of the start pointer before pop() operations
};
start and end are just void pointers that point to some location within the currently allocated memory block. If I push elements on the queue, I increment the end pointer by varsize. If I pop(), I just decrement the end pointer also by varsize.
I don't think I should post the functions code here, it's over 100 lines.
The question: is this considered a good or a bad practice? Why (not)?
Note: I'm aware that there are many other options for a queue in C. I'm just asking about the quality of this one.
EDIT: The implementation is available here:
http:// 89.70.149.19 /stuff/queue.txt (remove the spaces)
It's OK to use void * if you don't know the type and size of the objects to be stored in the queue (in fact, the C standard library follows the same approach, see the memcpy() and qsort() functions for some examples). However, it would be better to use size_t (or ssize_t if you need a signed data type) for specifying the size of the elements stored in the queue.
You really don't show us enough to be sure about your implementation. void* for the user data items is fine, you can't do much otherwise in C.
But I strongly suspect that you have an internal list element type that you use to manage the individual items, something like
struct list_item {
struct list_item* next;
void* data;
};
If that is the case and your start and end pointers are pointing to such elements, you definitively should use your element type in the struct queue declaration:
struct queue
{
struct list_item* start; //pointer to the beginning of queue
struct list_item* end; //-||- to the end
size_t memsize; //size of allocated memory, in bytes
size_t varsize; //size of a single variable, in bytes
struct list_item* initial_pointer; //position of the start pointer before pop() operations
};
For this to work you don't even have to expose the definition of struct list_item to the user of struct queue.
I have a unsigned char* head that is pointing to a certain addess in memory and now I have to create a typedef struct that I've declared starting at the location of that pointer...I am confused on how to do that!
Here is the declaration of the typedef
typedef struct {
struct block *next;
struct block *prev;
int size;
unsigned char *buffer;
} block;
My assignment involves implementing malloc, so I can't use malloc. A block is part of a free_list which contains all chunks of free memory blocks that I have in my program heap. Hence, the previous and next pointers that point to the previous and next free blocks of memory.
Head points to the start of the free_list. When I have to split say the first block of free memory to satisfy a malloc() request that needs less space then that free block has I need to move my head and create a new block struct there.
Hope this makes sense. If not, the assignment looks something like this
Your struct has no tag, so you need to give it one in order for it to point to itself:
typedef struct block {
struct block *next;
struct block *prev;
int size;
unsigned char *buffer;
} block;
If you're using C99 you can initialise the memory at head directly, if necessary, without declaring a temporary struct block:
*(block *)head = (block){NULL, NULL, 0, NULL};
You now have a struct block at the address head, as long as you cast it properly.
e.g.
((block *)head)->size = 5;
Or you assign a cast pointer to it:
block *p = (block *)head;
p->size = 5;
unsigned char* head = /* whatever you have assuming that it has a sufficient size. */;
/* Create a block in memory */
block* b = (block*)malloc(sizeof(block));
/*
* modify data in b here as you wish.
*/
b->next = 0;
b->prev = 0;
/* etc... */
/* copy b to head */
memcpy(head, b, sizeof(block));
/* free block */
free(b);
The above assumes that head has enough space to store an instance of block.
What it does is create a block, and copy the memory to the position of head, then free the allocated block.
From comments:
head points to the start of a place in memory where I can overwrite data...You may assume that I have enough space!
Then to obtain a properly typed pointer:
struct block *p = (struct block *)head;
and to have a copy of the block:
struct block b = *(struct block *)head;
The operating system will provide an API call to allocate blocks of memory that your malloc can carve up and provide to callers. In Linux/unix look at sbrk. In Windows look at the Win32 heap API. Your records will point into this block. Making sure no two allocated sections of the block overlap is the job of your allocator code.
It looks like your records are implementing a free list. So how are you going to allocate list nodes when you don't have an allocator (yet)? The usual solution is to do it in the free blocks themselves. So a free block has the structure:
typedef struct free_block {
struct free_block *next, *prev;
size_t size;
unsigned char buffer[1];
} FREE_BLOCK;
Now this data structure actually lies at the start of a free block. Its buffer has only 1 byte in the declaration, but the actual buffer is size bytes. Initially you'd have something like:
static FREE_BLOCK *free_list = sbrk(ARENA_SIZE);
free_list->next = free_list->prev = free_list;
free_list->size = ARENA_SIZE - offsetof(FREEBLOCK, buffer);
This places the whole arena on the free list as a single block. Your allocator will search free_list to find a block that's big enough, carve out the piece it needs, put the remaining small block (if any) back on the free list. For freeing, it will add the freed block to the list and coalesce adjacent blocks.
Simple free list allocators differ in how they choose the free block to allocate from: first fit, rotating first fit, best fit, worst fit, etc. In practice rotating first fit seems to work as well as or better than any of the others.
Incidentally, all of the common algorithms implemented with free lists don't need double links. Single ones will do.
Since this is an academic assignment, it should be fine to just call malloc (instead of an operating system API) to establish the big block (often called the "arena") your allocator will manage. You could also declare a big array of bytes.