pointer confusion with malloc - c

I have a working implementation of my code with a ton of mallocs. It has
struct* node myList;
struct node { ... } // contains stuff
struct* node_constructor(...) {
node* tempnode = (node*) malloc(sizeof(node));
node* next = ...;
... // some other info
}
and then in my main function I call
myList = node_constructor(myList,otherarguments...);
I'm thinking there's probably a way to do something like
temp = (node*) malloc(sizeof(node)*numberOfNodes);
for(i=0; i<numberOfNodes;i++) { temp[i].next = temp[i-1]; ... } // wrong?
temp[numberOfNodes-1]; // set myList equal to the last one
and get rid constructor function and all those individual mallocs, I just seem to be getting confused with what to do with my malloced space. So temp is a (node*), so I'm pretty sure my temp[i].next = temp[i-1] thing is wrong...and maybe some of the other ideas are too. If anyone has any advice/input, I'd appreciate it.

Ok, Sure, you could do that, kinda. As long as temp is big enough and you know that size beforehand. And temp would more likely be a void* or some generic container just to hang onto unspecified memory rather than node. (Because it's not a node, it's where all your nodes go. temp[x] when temp is malloced is kind of a hack).
But now you want to add another node to your list. How do you do that?
The individual mallocs let you add a single item to the list. And if you are in a situation where you want to add a number of items to your list, then you can just call the individual functions multiple times.
The idea of allocating a large pool of memory, and divvying it up into the piecemeal sections later is a valid idea and it has some performance benefits, but it's of limited niche use.
Allocating just enough memory for one more item is a lot more handy and common. You're not wrong, but trust me, learn how to do it the normal way first.

If you are going to back your list with an array there is no need to have next pointers - the next object is the next index in the array.
There are both advantages and disadvantages with an array list implementation compared to a linked list implementation.

Ideally, you would have a node like this:
typedef struct node
{
struct node* next;
struct node* prev; // optional for double-linked list
uint8_t* data;
size_t data_size;
} node_t;
and then create it as
result_t list_add (const void* data, size_t size)
{
if(list_is_full()) // if applicable
{
return list_is_full_error;
}
node_t* new_node = node_constructor(data, size);
if(new_node == NULL)
{
return memory_error;
}
list_add(new_node);
return ok;
}
static node_t* node_constructor (const void* data, size_t size)
{
node_t* new_node = malloc(*new_node);
if(new_node == NULL)
{
return NULL;
}
new_node->data = malloc(size);
if(new_node->data == NULL)
{
return NULL;
}
new_node->size = size;
memcpy(new_node->data, data, size);
return new_node;
}
static void list_insert (node_t* new_node)
{
// add the node to the linked list here
// set next/prev pointers of the new node and of adjacent nodes
// increase node counter (linked list size) if applicable
}

Related

how to build object from mmapped memory

I am building a custom allocator. I am calling mmap() the first time and then I am constructing an explicit freelist. Everything works fine, but when I need to split an existing block I do not seem to be able to initialize an object from a void* (my C fundamentals are quite rusty). I know it sounds confusing so here is the code that I have.
// this is the struct I am using to keep track of the free nodes
struct Node {
size_t header;
void* payload;
}
when I split, I decrease the size of the big node
void* split_block(Node* good_node, size_t reqsize) {
DECREASE_SIZE(good_node)
Node* prev_node = (Node*)(good_node -> payload);
Node* next_node = (Node*)((good_node -> payload) + 8);
}
I store the pointers to next and previous node. IMPORTANT, the pointer are inside the payload, specifically prev = payload, next=payload+8.
Now the problem. How do I construct a node from the raw memory (payload).
The code that does not work is this
// I omit the calculation of the address at which
// the split_part is going to end up
Node* split_part = GET_HEADER_POSITION(good_node, reqsize);
split_part->header = some_value;
split_part->payload = prev_node;
split_part->payload[1] = next_node;
I did not construct the object. But how can I do so, should not this work just like when I malloc memory?
Node* node = malloc(sizeof(Node));
Thank you for the attention.

Modified structs allocated in memory do not retain values after end of function

I have a couple of structs: A HashTable, which contains a table of pointers to WordNodes, and each WordNode contains a pointer to a List, which is a linked list made up of ListNodes.
I wrote a function to create a list and add list nodes to a WordNode:
int addWord(char* word, HashTable* hash_table, int id)
{
WordNode* current = calloc(1, sizeof(WordNode));
current = hash_table->table[hash];
// ...
if(current->docs == NULL){
// Create a new list, and initialize it
List* list = calloc(1, sizeof(List));
list->head = NULL;
list->tail = NULL;
int occur = 1;
ListNode* list_node = AddNode(list); // Create the first node in the list
current->docs = list; // Link the WordNode to the list
// Fill in relevant details of ListNode
list_node->id= &id;
list_node->occurrences = &occur;
list_node->next = NULL;
That is my function, but since it's been giving me trouble, I added a couple of lines inside it to test it:
printf("Testing:\n");
WordNode* wnode = calloc(1, sizeof(WordNode));
wnode = hash_table->table[hash];
List* my_list = calloc(1, sizeof(List));
my_list = wnode->docs;
ListNode* dnode = calloc(1, sizeof(ListNode));
dnode = my_list->head;
printf("Results: ocurrences: %d, id: %d\n",*((int*)dnode->occurrences),
*((int*)dnode->id));
printf("The dnode is %d\n", doc_node);
}
When called in main, the testing code inside the function produces the expected output:
Results: ocurrences: 1, id: 15
The dnode is 13867424
However, the same testing in the line immediately following the function call in main produces a weird output, even though the pointer seems to be pointing to the same address.
Results: ocurrences: 0, id: 54
The dnode is 13867424
Possibly relevant code from the function that adds a new node to the list:
ListNode* AddNode(List * list)
{
ListNode* node = calloc(1, sizeof(ListNode));
node->next = NULL;
if(list->tail == NULL){
list->head = node;
list->tail = node;
}
else{
list->tail->next = node;
list->tail = node;
}
return node;
}
I can't seem to figure out what I am doing wrong. It would seem to me that I am somehow handling the structs as local variables, even though I am allocating memory for them, which makes me think they shouldn't change after the function is done. It is probably a C-programmer's beginner mistake, but I can't seem to figure out where I am getting this wrong. Any help would be greatly appreciated.
One set of problems is in the code:
int addWord(char* word, HashTable* hash_table, int id)
{
…omitted…
int occur = 1;
ListNode* list_node = AddNode(list); // Create the first node in the list
current->docs = list; // Link the WordNode to the list
// Fill in relevant details of ListNode
list_node->id= &id;
list_node->occurrences = &occur;
You're storing a pointer to a parameter and a pointer to a local variable in your structure. Dereferencing either of those after the function returns is undefined behaviour. The space occupied by those could be reused by the compiler for any purpose at any time; they could become completely invalid (but probably won't).
Why do you have pointers in your structure for those two items? Surely, the structure should just contain a couple of int members, not int * members!
If, perchance, your code is compiling with warnings, don't submit it to SO; fix the warnings first. Or seek help on how to resolve the compiler warnings. They all matter. At this stage in your career, remember that the compiler knows a lot more about C than you do. If it warns about something in your code, the compiler is probably correct to be worried and the code is probably incorrect in some way.
Your code doesn't show where word is used — it could be that you are not copying that data either.

Allocating memory for a array of linked lists

Hi guys I'm new to linked lists, but I'm pretty sure that I know how they work, theoretically, I think I might having a syntax misunderstanding, or memory management error.
edit: My main purpose is to make a collection of lists which are indexed by the array, each array element is a head(or root) node. I'm having issues allocation dynamically this struct array.
What I'm doing is the following:
typedef struct item_list{
int item_name;
int item_supplier;
int item_price;
struct item_list *next
}node;
int i;
node ** shop_1 = (node **)malloc(shop_items_elements * sizeof(node));
for (i=0;i<=shop_items_elements;i++)
{
shop_1[i]->next=NULL;
}
I'm getting a segmentation fault while I try to give next at the element i the value of NULL.
The problem is that you are trying to allocate the memory for 20000 items as a contiguous block. Which implies that you actually haven't understood linked lists yet.
I think you are mixing up random access array functionality with pure linked lists which do not allow accessing individual items without traversing the list.
A linked list usually has a head and tail node which are initially NULL when there are no elements in the list:
node* head = NULL;
node* tail = NULL;
When adding a new node you first allocate it by using malloc with the size of a single node struct:
node* the_new_node = (node*)malloc(sizeof(node));
Initialize the struct members, specifically set next to NULL for each new node. Then use this append_node() function to append the node to the linked list:
void append_node(node** head, node** tail, node* the_new_node)
{
if(*tail == NULL)
{ // list was empty
*head = *tail = the_new_node;
}
else
{
(*tail)->next = the_new_node; // link previous tail node with new one
*tail = the_new_node; // set the tail pointer to the new node
}
Please note the pointer to pointers which are needed to update the head and tail pointers. Call the function like this for any given n you want to add:
append_node(&head, &tail, n);
Repeat this for every new node.
A much better way of encapsulating a linked list is putting the head and tail pointers into another struct
typedef struct linked_list
{
node* head;
node* tail;
} list;
and using an instance of that as first argument to append_node() (which I'll leave to you as an exercise ;)
When using such a linked list it is not possible to conveniently access the Nth node in less than O(n) since you have to follow all next pointers starting from the head node until you arrive at the Nth node.
EDIT: If you want to have the possibility to index the shop items and build a linked list from each of the elements I would suggest the following solution:
node** shop_1 = (node**)malloc(shop_items_elements * sizeof(node*));
int i;
for(i = 0; i < shop_items_elements; ++i)
{
node* n = (node*)malloc(sizeof(node));
n->next = NULL;
shop_1[i] = n;
}
You first allocate an array of pointers to node pointers which have to be allocated individually of course. Take a look at this diagram for reference:
The actual node instances may be larger than a pointer's size (unlike drawn in the diagram) which is the reason why you allocate N * sizeof(node*) in a block instead of N * sizeof(node).
Your code needs to look like this
int i;
node * shop_1 = (node *)malloc(shop_items_elements * sizeof(node));
for (i=0;i<shop_items_elements;++i)
{
shop_1[i].next=NULL;
}
Your malloc statement has allocated an array of nodes, not an array of pointers to nodes. (If that is what you wanted instead, then you would have had to initialize each pointer with a further malloc call before trying to assign a value to a field within the node pointed to.)

Unable to reverse a linked list

I was trying to reverse a linked list, however whenever I execute the following function, I get only the last element. For example, if the list contained 11,12,13 earlier. After executing the function, it contains only 13. Kindly point out the bug in my code
void reverselist() {
struct node *a, *b, *c;
a = NULL;
b = c = start;
while (c != NULL) {
c = b->next;
b->next = a;
a = b;
b = c;
}
start = c;
}
Doesn't your loop guard insure that start is null?
If you aren't using start to identify the first element of the list, then the variable you ARE using is still pointing to what WAS the first element, which is now the last.
c is a helper pointer.
void reverselist()
{
struct node *a, *b, *c;
a=NULL;
b=start;
while(b!=NULL)
{
c=b->next
b->next=a;
a=b
b=c
}
start=a;
}
// You should assume that Node has a Node* called next that
// points to the next item in a list
// Returns the head of the reversed list if successful, else NULL / 0
Node *reverse( Node *head )
{
Node *prev = NULL;
while( head != NULL )
{
// Save next since we will destroy it
Node *next = head->next;
// next and previous are now reversed
head->next = prev;
// Advance through the list
prev = head;
head = next;
}
return previous;
}
I would have made a prepend function, and done the following:
struct node* prepend(struct node* root, int value)
{
struct node* new_root = malloc(sizeof(struct node));
new_root->next = root;
return new_root;
}
struct node* reverselist(struct node* inlist)
{
struct node* outlist = NULL;
while(inlist != NULL) {
struct node* new_root = prepend(outlist, inlist->value);
outlist = new_root;
inlist = inlist->next;
}
return outlist;
}
Have not tested this, but guess you grasp the idea of it. Might be just your variable names, which don't describe anything, but I think this approach is cleaner, and easier to understand what actually happens.
EDIT:
Got a question why I don't do it inplace, so I'll answer it here:
Can you do it inplace? Are you sure you don't wish to keep the
original list?
Do you need to do it inplace? Is the malloc to time consuming/is this a performance critical part of your code? Remember: premature optimization is the root of all evil.
Thing is, this is a first implementation. It should work, and not be optimized. It should also have a test written before this implementation is even thought of, and you should keep this slow, un-optimized implementation until the test passes, and you have proved that it's to slow for your use!
When you have a passing unit test, and proven the implementation to be to slow, you should optimize the code, and make sure it still passes the test, without changing the test.
Also, is it necessary inplace operations which is the answer? What about allocating the memory before reverting it, this way you only have one allocation call, and should hopefully get a nice performance boost.
This way everyone is happy, you have a cleaner code and avoid the risk of having Uncle Bob showing up at your door with a shotgun.

Allocate a consecutive linked list in c

Im trying to create a linked list in c. The twist is that I want to allocate the memory for the list so that all the nodes are consecutively stored in memory.
Maybe an array structure is the way to go.
Any ideas?
The obvious way would be to allocate a number of nodes in a block, then link them together into a free list. When you need to add a node to your linked list, you'll grab the one from the head of your free list. When you want to delete a node, you link it back onto the free list:
struct node {
struct node *next;
// other data here.
};
node *free_list;
#define block_size 1024
void initialize() {
free_list = malloc(block_size * sizeof(struct node));
for (i=0; i<block_size-1; i++)
free_list[i].next = &free_list[i+1];
free_list[block_size-1].next = NULL;
}
struct node *alloc_node() {
struct node *ret;
if (free_list == NULL)
return NULL;
ret = free_list;
free_list = free_list->next;
return ret;
}
void free_node(struct node *n) {
n->next = free_list;
free_list = n;
}
If you're looking at a linked list, don't worry about where in memory they are. That's what the pointers on the nodes are for.
If you want them sequential, allocate an array.
Yes, use an array. More interesting is why you want this. If your program requires this to work, then you'll need to make sure your array is big enough to store all the nodes that might be allocated. If not, you can allocate batches of nodes.
FYI. I've seen this strategy used in the past on the assumption that sequentially allocated nodes would result in fewer cache misses when searching the list. In the system of interest, that didn't actually give much a performance improvement. [ Not enough profiling of course!.]
You could do something like this
struct node
{
int data;
struct node *next;
};
struct node linkedlist[50];
This would allocate space for linked list structure in contiguous locations.

Resources