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?
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;
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!
#include <stdlib.h>
struct st *x = malloc(sizeof *x);
Note that:
x must be a pointer
no cast is required
include appropriate header
Related
I was looking forward to make an array of struct just like [ obj, obj, obj ].
I got this struct:
struct obj {
char name[MAX_NAME];
char desc[MAX_TEXT];
bool asible;
};
How can I make it?
I tried
struct obj **objInRoom = malloc(sizeof(struct obj));
But when I iterate in it, it doesnt have anything :D
I chose this solution because I need to put that array of struct into this struct:
struct room {
struct obj **objts; //HERE
int qntty_objts;
struct interact **interacts;
int qntty_interacts;
};
If you need to have a double pointer for some reason, then you can do something like this struct obj *objInRoom = malloc(sizeof(struct obj)); and then assign address of objInRoom to your struct room->objts=&objInRoom.
struct obj **objInRoom = malloc(sizeof(struct obj));
If I simplifies, in your try you are allocating an area for a struct and trying to assign its address to a 'struct obj address' address holder which is struct obj**. But you should use struct obj * to hold the address of newly allocated area.
Which in this case your struct room should be like this:
struct room {
struct obj *objts; //struct obj** to struct obj*
int qntty_objts;
struct interact **interacts;
int qntty_interacts;
};
You should assign your newly allocated area like this:
struct obj *objInRoom = (struct obj*)malloc(sizeof(struct obj));
But in this case you only allocated the area for one struct obj element. To increase this area you can take the backup of your previous data and allocate new area for more size. For example to increase your allocated area two times:
//cap is integer defined before to hold capacity information of array
struct obj *backup = (struct obj*)malloc(2*cap*sizeof(struct obj));
for(int i = 0; i < cap; ++i)
backup[i] = objInRoom[i];
free(objInRoom); //to prevent memory leak, because we allocated new area for our incremented sized array.
objInRoom = backup;
cap *= 2;
Or you can simply use realloc to increase your array capacity if an allocation happened before with malloc or calloc, realloc creates an array with desired size and holds the previous data:
objInRoom = (struct obj*)realloc(objInRoom, 2*cap*sizeof(struct obj))
Note: Always cast your malloc operation to your desired pointer type because it returns 'void *' for default.
Note 2: Always check outputs from malloc, realloc and calloc; they return NULL in case of error.
I'm trying to allocate memory for a pointer, but have a reference to the address of that pointer. I'm still pretty new to C and this is my first time working with double pointers really.
So I have two structures and they look like this:
typedef struct myNodes {
int data;
struct myNodes *next;
} listElement;
typedef struct {
listElement **ptrToElements;
} myStruct;
In another file, I'm trying to dynamically allocate memory for my pointer by doing something like this:
myStruct *myStruct = malloc(sizeof(*myStruct));
*(myStruct->ptrToElements) = (listElement*)malloc(sizeof(listElement));
but I keep encountering a segmentation fault from doing so. What could be the issue? Thanks!
The problem is with
*(myStruct->ptrToElements) ....
statement. Before dereferencing myStruct->ptrToElements, you need to make sure it points to a valid memory.
To elaborate, you allocate memory for myStruct. Fine.
That constitutes allocating memory for the member ptrToElements. Good.
Question: What does ptrToElements points to?
Answer: Indeterministic.
So, when you try to derefernce a pointer which points to an indeterministic memory address, it's pretty much invalid memory address and attempt to do so will invoke undefined behavior.
Solution: You need to allocate memory for myStruct->ptrToElements before you can go ahead and dereference it.
having said that, please see do I cast the result of malloc?
You define the structure to contain a pointer to a pointer to a listElement
typedef struct {
listElement **ptrToElements;
} myStruct;
As Sourav Ghosh wrote, you try to assign a value to the pointer where ptrToElements would point to without allocating memory.
Probably you should change the pointer type to
typedef struct {
listElement *ptrToElements;
} myStruct;
and when allocating the memory
myStruct *myStruct = malloc(sizeof(*myStruct));
/* If the list can be empty, initialize root with NULL pointer */
myStruct->ptrToElements = NULL;
/* when you add the first list element */
myStruct->ptrToElements = malloc(sizeof(listElement));
myStruct->ptrToElements->data = someValue;
/* at least for the last element you add here you should initialize next */
myStruct->ptrToElements->next = NULL;
Don't forget to handle errors, e.g. malloc returning NULL.
I think this is what you want:
typedef struct myNodes {
int data;
struct myNodes *next; // not clear what this pointer is used for...
} listElement;
typedef struct {
listElement *ptrToElements;
} myStruct;
// Memory Allocation
// allocate myStruct pointing to an array of N listElements
myStruct *ms = malloc(sizeof(myStruct));
ms->ptrToElements = malloc(N * sizeof(listElement));
// element access
for (int i = 0; i < N; i++) {
listElement *le = ms->ptrToElements[i];
le->data = ...
le->next = NULL; // not clear what this pointer is used for...
}
// Memory deallocation
free(ms->ptrToElements);
free(ms);
I'm trying to figure out how to initialize a struct if I'm passed a memory location, the situation below is what I'm trying to do, but it throws "invalid initializer" shortened to relevant code
#ifndef PAGE_ALLOC_H
#define PAGE_ALLOC_H
typedef struct listNode
{
struct listNode *prev;
struct listNode *next; // prev/next element in linked list
char * address;
} listNode;
#endif
_____________________________________________
#include "page_alloc.h"
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char ** args)
{
void * memptr;
int test = posix_memalign(&memptr, 2, 128); // test is > 1, values such as 16 and 22 is this ok? It does seem to return a valid memory address though, but can't test until struct lets me initialize to it...
listNode testNode = memptr; // this throws improper initialization flag, but how else do I do tell //the struct where the eligible memory is?? Isn't that what malloc does? Return a point to acquired //memory
// Now this is what I imagine doing after telling testNode where its allocated memory
testNode ->prev = somePreviousNode; // etc.
}
I'm obviously doing something wrong but what? I'm sorry if this is a dumb question but I can't find any examples of posix_memalign nor can I find an explanation of properly initializing structs with a pointer to allocated memory. I need to dynamically add nodes because this is for a doubly linked list pointing to memory locations (used for keeping track of "pages")
Thanks for any insight!!!
testNode is an object of the structure and you are assigning a pointer (memptr) to it:
listNode testNode = memptr;
Instead create a pointer to listnode and assign the allocated memory to it:
listNode *testNode = memptr;
Note: The value of the alignment parameter should satisfy two conditions:
should be a multiple of sizeof(void*)
should be a power of 2.
For eg,
if on your machine, sizeof(void*) = 4, then the acceptable value is 4,8,16....
if on your machine, sizeof(void*) = 8, then the acceptable value is 8,16,32...
I'm having syntax error everywhere, bad understanding of syntax for ADTs and memory handling. I need a struct that references to itself (other sections) in the next and prev. Am I doing it right? I get errors...
struct _header * header;
typedef struct _header {
int signiture;
int size;
header_t* next;
header_t* prev;
} header;
I also want to initialise the first 32 bytes within the memory with a header (this is not going well also..):
//this is to reference the memory block later
static int *free_list_ptr;
void function(u_int32_t size){
memory = (byte*) malloc(size);
header firstHead = malloc(sizeof(_header));
free_list_ptr = firstHead = memory;
firstHead->prev = free_list_ptr;
firstHead->next = free_list_ptr;
}
You can't reference a typedef while creating it, so you should do:
typedef struct a_header {
int signiture;
int size;
struct a_header* next;
struct a_header* prev;
} header;
header* the_header;
Avoid names with leading underscore - they are reserved for the system things.
Please try this:
typedef struct _header *lpheader;
typedef struct _header {
int signiture;
int size;
lpheader next;
lpheader prev;
} header, *lpheader;
Also why do you need 32 bytes worth of space for this structure? You should rather be using sizeof(_header).
You are thinking too complicated, your typedef is too late and you are using the wrong name inside the declaration of the struct.
typedef struct header header; // <- forward declare "struct header" and identifier "header"
struct header {
int signiture;
int size;
header* next;
header* prev;
};
For the sequel, I didn't really understand what you wanted to do. What is for sure that you use bizarre names in there that aren't declared and that you cast the return of malloc.
This is your current problem.
memory = (byte*) malloc(size);
header firstHead = malloc(sizeof(header));
free_list_ptr = firstHead = memory;
You allocate size and store its location as a byte* into memory.
Then you (correctly) allocate one header structure, and store that space's allocation into firstHead.
Then you throw that away (leaking that memory) by setting firstHead to the wrongly sized allocated space of memory, and then set free_list_ptr to the same wrongly sized allocated space.
Since your current pointer isn't holding enough memory, you get into trouble when you try to use the offsets of next and prev.
I suspect you need this:
memory = null;
header firstHead = malloc(sizeof(header));
memory = free_list_ptr = firstHead;
This will set the pointers memory and free_list_ptr to both point at the allocated space pointed at by firstHead.
I don't know why you are using two different pointers to track memory and free_list_ptr. My intuition is that 1 of these are probably sufficent for your purposes.
I'm not sure exactly what I need to use as an argument to malloc to allocate space in the table_allocate(int) function. I was thinking just count_table* cTable = malloc(sizeof(count_table*)), but that doesn't do anything with the size parameter. Am I supposed to allocate space for the list_node_t also? Below is what I am working with.
In the .h file I'm given this signature:
//create a count table struct and allocate space for it
//return it as a pointer
count_table_t* table_allocate(int);
Here are the structs that I'm supposed to use:
typedef struct list_node list_node_t;
struct list_node {
char *key;
int value;
//the next node in the list
list_node_t *next;
};
typedef struct count_table count_table_t;
struct count_table {
int size;
//an array of list_node pointers
list_node_t **list_array;
};
count_table* cTable = malloc(sizeof(count_table*))
is wrong. It should be
count_table* cTable = malloc(sizeof(count_table));
Also, you must allocate memory for list_node_t also seperately.
EDIT:
Apart from what Clifford has pointed about allocating memory for the list node, I think the memory allocation should also be taken care for the char *key inside of the list node.
Your suggestion: count_table* cTable = malloc(sizeof(count_table*)) would only allocate space for a pointer to a count_table.
You'd need
count_table* cTable = malloc(sizeof(count_table) ) ;
Each list node would be separately allocated and cTable->size and cTable->list_array and the last list_node_t::next updated accordingly. Maintaining a pointer to the last node added would make adding nodes faster.
I am not sure why count_table::list_array is of type list_node_t** rather than just list_node_t* (and equally called list_array rather than just list). Is it your intention that it is both an array and a list at the same time? That would be somewhat redundant. The member need only be a pointer to the first node, successive nodes are then accessed via list_node::next
Given that the int is a "size" parameter for the created count_table_t, it appears that you are supposed to both allocate the count_table_t itself, as well as initialise its members.
Initialising the list_array member also involves a memory allocation, so it would look like:
count_table_t *table_allocate(int size)
{
count_table_t *table = malloc(sizeof *table);
int i;
table->size = size;
table->list_array = malloc(size * sizeof table->list_array[0]);
for (i = 0; i < size; i++)
table->list_array[i] = NULL;
return table;
}
However, you also need to check for some error conditions: the multiplication of size by sizeof table->list_array[0] could overflow, and either of the malloc() calls could fail. So the function should actually look like this:
count_table_t *table_allocate(int size)
{
count_table_t *table;
int i;
/* Check for overflow in list allocation size */
if (size < 0 || size > (size_t)-1 / sizeof table->list_array[0])
return NULL;
table = malloc(sizeof *table);
if (table == NULL)
return NULL;
table->size = size;
table->list_array = malloc(size * sizeof table->list_array[0]);
if (table->list_array == NULL) {
free(table);
return NULL;
}
for (i = 0; i < size; i++)
table->list_array[i] = NULL;
return table;
}
(Note that (size_t)-1 is a constant equal to the maximum value of a size_t, which is the type of the parameter to malloc()).
In addition to the other posters who point out that you're only allocating enough space for the pointer, not the space the data you want will occupy, I strongly urge you to do things like this:
count_table* cTable = malloc(sizeof(*cTable));
This will help you in case the type of cTable ever changes, you won't have to adjust two parts to that line, just the type.