Preserving Structs without Dynamic Allocation - c

I've been battling with this problem for a few hours.
I have a doubly linked list implementation that does not require dynamic memory allocation.
Here's the insertion method. It inserts elem right before before. The struct list has two members, struct list_elem *next and struct list_elem *prev. list_elem is a struct that holds some data. Please note that this list implementation is correct. The problem is with the way I am using it. Please read on.
void list_insert(struct list_elem *before, struct list_elem *elem) {
/* "before" has to be an interior node or tail node to be able to insert "before" it */
assert (is_interior(before) || is_tail(before));
assert (elem != NULL);
elem->prev = before->prev;
elem->next = before;
before->prev->next = elem;
before-> = elem;
}
The way this list is initialized is as follows:
void list_init(struct list *list) {
assert(list != NULL);
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
My main class does the following:
struct list some_list;
static struct list_elem head;
some_list.head = head;
static struct list_elem tail;
some_list.tail = tail.
list_init(&some_list);
This basically creates two static list_elem structs, head and tail. And passes it into the initialization function which will wire them up together.
Now to create an element, I do the following - here's what I am doing wrong
struct list_elem element_struct;
/* Initialize element_struct members here */
struct list_elem *data = &element_struct;
list_insert( list_begin(some_list), data);
Now this works to insert one item. Since some_list.head will point to data which will point to some_list.tail. My problem is that I do this in a loop. So, as any list does, it will enter multiple data in there. I either get a segfault or some other error saying my element is not an interior or tail node (due to assert) since in each loop iteration, the data struct, element_struct will be reinitialized. (list_elem holds pointers to each other).
So my question is, how would I preserve the nodes that have been inserted? The list is not supposed to use any dynamic allocation itself. In that case, would I dynamically allocate my list_elem structs, and pass a dynamically allocated element into the list?
If so, how can I dynamically allocate a struct?

If you need to dynamically-allocate a struct instance, it's as simple as MyStruct *p = malloc(sizeof(*p));, and then an associated free(p); at some point.

Related

How do I delete a doubly linked list in C?

I've created a doubly linked list, filled it with values and now I want to delete it and remove all the values to avoid memory leaks. Here's what I wrote as well as the structs that were used when creating the doubly linked list. Both those functions will be called towards the end of the main function.
struct node
{
struct node *next;
struct node *prev;
char *value;
};
// The type for a list.
typedef struct list
{
struct node head;
} List;
// The type for a list position.
typedef struct list_pos
{
struct node *node;
} ListPos;
void list_destroy(List *lst)
{
List p,q;
p = *lst;
while (p)
{
q = p.head->next;
free(p);
p = q;
}
*lst = NULL;
}
// Remove the value at the position and return the position of the next element.
ListPos list_remove(ListPos pos)
{
}
You appear to have the right general idea: you walk the list and free each node, making sure to grab any needed data from each node (in particular, the pointer to the next node) while the node holding it still exists. Your case differs from some that you might have seen, however, because instead of handling the overall list via a bare pointer to the head node, you have a separate object, of a separate type (List / struct list), to represent the list itself. This approach has much to recommend it, including, especially, the use of (apparently) a dummy head node, which provides for a variety of algorithmic simplifications. This is usually how I write a linked list.
But because struct list is not struct node, you cannot set a list pointer equal to a node pointer. Instead, create a struct node * to track your position. The first node to free would be the one referenced by struct node *to_free = lst->head.next, and the one after that would be the one referenced by to_free->next.
Note that you might need to free the struct list, too.

Freeing a struct

I have a linked list struct on me, and I used a node struct to help me store data and know where each node is pointing to. In the creation of my list, I did this:
struct list {
struct node *Head;
struct node *Tail;
}
struct node{
int val;
struct node * next;
}
struct list create_list(){
struct list new_list;
new_list = malloc(sizeof(struct list));
}
Then, when I am trying to free the list that I malloced for, I did this
void free_list(struct list linked_list){
free(linked_list);
}
However, I realize that I may have malloced wrong, because when you malloc, you need to assign it to a pointer. When I want to free the linked_list that I originally malloced for, nothing really changes.
I think this may be because the linked_list that I sent into free() is not a pointer, thus no changes have been made. I tried adding & and * to it, but I end up getting errors....
Any tips or help is appreciated.
Edit:
Fixed Typo on the struct list.
This is hw, so I cannot change the parameters of the functions, which is what is giving me a hard time freeing the linked list I made. This is because the function free_list() cannot change its parameter into a pointer linked list, so I don't know exactly what to do.
I will also take note of when I am mallocing for the linked list in the create_list function.
Yay for passing the linked list around by value rather than on the heap for something that small.
Is this more like what you want:
struct list create_list(){
struct list new_list = { NULL, NULL };
return list;
}
void free_list(struct list linked_list){
struct node *next;
for (struct node *node = linked_list.Head; node; node = next;)
{
temp = node->next;
free(node);
}
}
Thus freeing only the list nodes that were allocated with malloc().

Why use dynamic memory allocation(i.e. malloc()) when implementing linked list in c?

Okay this question may sound stupid to the amateur programmers . But seriously this is bothering me and a solemn answer to this doubt of mine is welcomed. I have just started to take my first ever course in data structures. And what is bothering me is this:
Assuming C is used,
//Implementing a node
struct Node
{
int data;
struct *Node;
};
Now while creating a node why do we use the dynamic memory allocation technique where we use malloc(). Can't we just create a variable of type ' Struct Node '.
i.e. something like:
struct Node N1;
//First node - actually second where !st Node is assumed to be Head.
struct Node *Head = &N1;
struct Node N2;
N2.(*Node) = &N1;
Well some parts of my code may be incorrect because I am only a beginner and not well versed with C. But by know you may have understood what I basically mean. Why don't we create variables of type Node of an Array of type Node to allocate memory t new nodes why get into the complexity of dynamic memory allocation?
First off, you have an error in how you declare your struct. struct * by itself does not denote a type. You have to give the full type name:
struct Node
{
int data;
struct Node *Node;
};
You can certainly use local variables as above to make a linked list, however that limits you to a fixed number of list elements, i.e. the ones you explicitly declare. That would also mean you can't create a list in a function because those variables would go out of scope.
For example, if you did this:
struct Node *getList()
{
struct Node head, node1, node2, node3;
head.Node = &node1;
node1.Node = &node2;
node2.Node = &node3;
node3.Node = NULL;
return &head;
}
Your list would be restricted to 4 elements. What of you needed thousands of them? Also, by returning the address of local variables, they go out of scope when the function returns and thus accessing them results in undefined behavior.
By dynamically allocating each node, you're only limited by your available memory.
Here's an example using dynamic memory allocation:
struct Node *getList()
{
struct Node *head, *current;
head = NULL;
current = NULL;
// open file
while (/* file has data */) {
int data = /* read data from file */
if (head == NULL) { // list is empty, so create head node
head = malloc(sizeof(struct Node *));
current = head;
} else { // create new element at end of list
current->next = malloc(sizeof(struct Node *));
current = current->next;
}
current->data = data;
current->Node = NULL;
}
// close file
return head;
}
This is psedo-code that doesn't go into the details of reading the relevant data, but you can see how you can create a list of arbitrary size that exists for the lifetime of the program.
If these variables are local, defined inside a function's scope (i.e. stored on the stack), you shouldn't do this, because accessing them after leaving their scope will result in undefined behavior (their contents will likely be overwritten as you call other functions). In fact, any time you return a pointer to a local, stack based variable from your function, you are doing the wrong thing. Given the nature of C, this is problematic since nothing will warn you you are doing something wrong, and it will only fail later when you try to access this area again.
On the other hand, if they are declared as global variables (outside any other function), then you are simply limited by the number of variables declared that way.
You can potentially declare many variables, but keeping track of which one is "free" for use will be painful. Sure, you can even go a step further and say you will have a global preallocated array of nodes to prevent using malloc, but as you are doing all this you are only getting closer to writing your own version of malloc, instead of sticking to the existing, dynamic one.
Additionally, all preallocated space is wasted if you don't use it, and you have no way of dynamically growing your list in runtime (hence the name dynamic allocation).
Here is some good reasons to use dynamic memory
When you declare node struct Node N1;this node will store on stack memory. After scope of the node that will get destroy auto.But in case of dynamic you have handle to free the memory when you done.
When you have some memory limitation.
When you don't know the size of array then dynamic memory allocation will help you.
One issue could be that you cannot use another function to add a new node to your list.
Remember that automatic variables - like the ones created by struct Node node100; - have scope only inside the function in which they are defined. So when you do something like this:
int main()
{
struct Node *head;
/* Some code there you build list as:
head ---> node1 ---> node2 --> .. ---> node99
*/
/* Add a new node using add_node function */
add_node(head, 555);
/* Access the last node*/
}
void add_node(struct Node *head, int val)
{
/* Create new node WITHOUT using malloc */
struct Node new_node;
new_node.data = val;
/* add this node to end of the list */
/* code to add this node to the end of list */
/* last_element_of_list.next = &new_node*/
return;
}
Now you think that you have added a new node to the end of the list. But, unfortunately, its lifetime ends as soon as the add_node function returns. And when you try to access that last node in your main function your program crashes.
So, to avoid this situation you will have put all your code in one single function - so that the lifetime of those nodes do not end.
Having all your code in ONE function is bad practice and will lead to many difficulties.
This was one situation that asks for a dynamic memory allocation, because, a node allocated with malloc will be in scope untill it is freed using free, and you can put code that do different things in different functions, which is a good practice.
You don't have to use dynamic memory to create a linked list, although you definitely don't want to create separate variables for each node. If you want to store up to N items, then you'd need to declare N distinct variables, which becomes a real pain as N gets large. The whole idea behind using a linked list is that it can grow or shrink as necessary; it's a dynamic data structure, so even if you don't use malloc and free, you're going to wind up doing something very similar.
For example, you can create an array of nodes at file scope like so:
struct node {
int data;
struct node *next;
};
/**
* use the static keyword to keep the names from being visible
* to other translation units
*/
static struct node store[N]; /* our "heap" */
static struct node *avail; /* will point to first available node in store */
You the initialize the array so each element points to the next, with the last element pointing to NULL:
void initAvail( void )
{
for ( size_t i = 0; i < N - 1; i++ )
store[i].next = &store[i + 1];
store[N - 1].next = NULL;
avail = store;
}
To allocate a node for your list, we grab the node avail points to and update avail to point to the next available node (if avail is NULL, then there are no more available nodes).
struct node *getNewNode( void )
{
struct node *newNode = NULL;
if ( avail ) /* if the available list isn't empty */
{
newNode = avail; /* grab first available node */
avail = avail->next; /* set avail to point to next available node */
newNode->next = NULL; /* sever newNode from available list, */
} /* which we do *after* we update avail */
/* work it out on paper to understand why */
return newNode;
}
When you're done with a node, add it back to the head of the available list:
void freeNode( struct node *n )
{
n->next = avail;
avail = n;
}
We're not using dynamic memory in the sense that we aren't calling mallic or free; however, we've pretty much recapitulated dynamic memory functionality, with the additional limitation that our "heap" has a fixed upper size.
Note that some embedded systems don't have a heap as such, so you'd have to do something like this to implement a list on such systems.
You can write a singly linked list with out malloc , but make sure the implementation is done in main. but what about writing program for traversing , finding least number ,etc . these struct node variables will go out of scope .
struct node{
int a;
struct node* nextNode;
};
int main()
{
struct node head,node1,node2;
head.a=45;
node1.a=98;
node2.a=3;
head.nextNode=&node1;
node1.nextNode=&node2;
node2.nextNode=NULL;
if(head.nextNode== NULL)
{
printf("List is empty");
}
struct node* ptr=&head;
while(ptr!=NULL)
{
printf("%d ",ptr->a);
ptr=ptr->nextNode;
}
}

Trying to create an empty linked list in C

I'm trying to create an empty linked list, which asks the user for the maximum number of terms that the list can hold. (I didn't add my code for that as its simply a printf). I then have to create a new function which asks the user to insert input into the previously created list.
My question is, how do I make the create_q() function return the empty list?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_t {
int value;
int priority;
struct node_t *next;
}node;
typedef struct priority_linked_list {
struct name *head;
int current_size;
int max_size;
}priority_list;
typedef node *Node;
typedef priority_list *List;
void create_q(int max_terms) {
node *head = NULL;
node *next = NULL;
List *current_size = 0;
List *max_size = max_terms;
}
In C, linked lists are usually implemented as a series of nodes stored on the heap that point to eachother. The heap is a persistent memory area that runs throughout the life-cycle of the program.
When you create a variable normally in a C function, and the function returns, the variable that you created is no longer accessible. However when you create something on the heap in a function, and the function is returned, the data you allocated on the heap is still there. However, you have no way of accessing it-- unless the function returns a pointer.
So what you would do for create_q() would be to create the linked list on the heap (using a function in stdlib.h called "malloc"), and then you would return a pointer to your first node, letting the main function know where on the heap to find the first node. Then that first node would have a pointer in it, telling the program where on the heap to find the second node, and so forth.
However, you're probably approaching linked lists the wrong way. Unless this is for some sort of homework project, you probably wouldn't want to create an empty linked list. One of the benefits of a linked list is that it's a dynamic structure in which you can easily insert new nodes. You could still have some variable keeping track of the maximum size you want the list to be, but you probably wouldn't want to actually create the nodes until you had to.
Just keep in mind what a linked list is. It's a set of nodes floating on the heap (in C) that each store some data, and contain a pointer to the next node floating on the heap. All you need, to access the linked list, is a pointer to the first node. To add a new node, you simply "walk" through the list till you reach the last node, and then create a new node and have the old-last node point to it.
Is this what you had in mind?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node_t
{
int value;
int priority;
struct node_t *next;
};
static int current_size;
static int max_size;
static struct node_t* head = NULL;
struct node_t* create_q(int);
struct node_t* create_q(int max_terms)
{
int i; // loop counter/index
current_size = max_terms;
max_size = max_terms;
if( NULL == (head = malloc(sizeof(struct node_t)*max_terms)))
{ // then, malloc failed
perror("malloc failed for struct node_t list");
exit( EXIT_FAILURE );
}
// implied else, malloc successful
// set all fields to '0,0,Null'
memset( head, 0x00, sizeof(struct node_t)*max_terms);
// set all next links, except last link
for(i=0;i<(max_terms-1);i++)
{
head[i].next = &head[i+1];
}
// set last link
head[i].next = NULL;
return( head );
} // end function: create_q
I suspect you are looking for something like the following for creating or initializing your priority linked list.
/*****
* alloc_q - allocate memory for the priority linked list
*/
struct priority_linked_list *alloc_q(void)
{
struct priority_linked_list *list;
list = malloc(sizeof(*list));
return list;
}
/******
* init_q - initialize the priority linked list
*/
void init_q(struct priority_linked_list *list, int max_terms)
{
list->head = NULL;
list->current_size = 0;
list->max_size = max_terms;
}
/******
* create_q - allocate AND initialize the priority linked list
*/
struct priority_linked_list *create_q(int max_terms)
{
struct priority_linked_list *list;
list = alloc_q();
if (list == NULL) {
return NULL;
}
init_q(list, max_terms);
return list;
}
Allocation of nodes and their addition/removal to/from the list would be handled separately.
There may be typos in the above (I have not tested it). However, it should be enough to get you on the path you want.
Hope it helps.

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.)

Resources