I have a linked list struct, i want to pass one node (another struct) pointer to a function (the node is part of the linked list, but i'm passing the node seperately to a deleter function
I want it to copy the next node data into itself (overriding its data), and to delete the next node, thus deleting itself (this part is working)..
I made it check whether the passed node is the last node in the list, and if so, to delete itself.
I don't know how to delete structs from the stack (i know i can malloc() and free() it using the heap memory).
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int data;
struct node * next;
}node;
typedef struct {
struct node * head;
}linked_list;
void print_list(linked_list * list) {
node *current = list->head;
while (current) {
printf("Current node has %d\n",current->data);
current = current->next;
}
}
void delete_node(node * n) {
node * next = n->next;
if (next) {
n->data = next->data;
n->next = next->next;
}
else {
*n = NULL; /*This of course won't compile because assigning void* (null) to node variable
but if i make n point to NULL, nothing will happen because i'm inside a function
and the pointer is duplicated (the passed pointer will still work) */
}
}
void main(){
node first;
node second;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = NULL;
linked_list l;
l.head = &first;
print_list(&l);
delete_node(&second);
print_list(&l);
}
As others have said, you can't.
If you want to be able to store both allocated (by malloc) and non-allocated (static or automatic) storage objects in your list and have a "delete" function that removes objects from the list and frees them, you need to store as part of each list member a flag indicating whether it's in allocated storage or not, and only free the ones which are.
Also note that you'll be in big trouble if the lifetime of the structure with automatic storage ends before you remove it from the list! If dealing with this is confusing at all for you, then you would probably be better-off just using allocated storage (malloc) for all list members.
You can't :)
On most computer architectures, local variables are either allocated directly on a CPU register or on the stack. For local variables allocated on the stack, the top of the stack (the same stack that is used to hold the return addresses of function calls) is manipulated to make space for them when a function enters, and it is restored to "release" the memory when the function exits. All this stack management is handled automatically by the compiler.
You can use the 'free' operator for freeing / deleting a malloc assigned object in the memory. For that, in your code you can write :
free(n);
Related
I was making a dynamic linked list in C, something similar to what we have in Java.
I was wrapping the element/value inside a struct which has the value and the address of the next node. I didn't feel like passing an instance of the struct itself, so I made a method that accepts the value and adds that value in the struct((you can say this struct is abstracted out, someone using the method won't know that there a struct being used inside the method) and then adds that struct to the list.
To test the code, I added 5 different integers and that struct I made inside the method got the same memory address during all the 5 additions.
This code was compiled using gcc and was written and tested in ubuntu.
struct node {
void* value; // literal values can't be passed in here, only address can be passed
struct node* next; // poninter to the next node
};
typedef struct {
size_t size; // size of the linked list
struct node* head; // head node of the list, always points to the first element in the list
} link_list;
void link_list_add(link_list * list, struct node * ele) {
// if size is zero, simply add the node to the list
if(list->size==0) {
list->head = ele;
ele->next = NULL;
}
else {
// add the new node to the front of the list and make in point towards what is being pointed by the list head
ele->next = list->head;
list->head = ele;
}
list->size++;
}
// does the same thing as the previous method, the only difference being that it takes the address of the element that needs to add and makes the wrapper node struct for it.
void link_list_add_ele(link_list * list, void * ele){
struct node eleNode = {ele, NULL}; // this gives the same address every single time.
link_list_add(list, eleNode);
}
This defines a local variable:
struct node eleNode = {ele, NULL}; // this gives the same address every single time.
It is allocated when the link_list_add_ele function is called and freed when the function returns. The next time you call the function, its memory might be reused.
What you're looking for is a dynamic memory allocation (like new in Java):
void link_list_add_ele(link_list * list, void * ele){
struct node *eleNode = malloc(sizeof(struct node));
eleNode->value = ele;
eleNode->next = 0;
link_list_add(list, eleNode);
}
But remember that such memory would also need to be explicitly freed by a call to free(), as C doesn't have a garbage collector.
Stack memory like struct node eleNode = {ele, NULL}; is no longer valid once the function returns. After the function returns the memory will be reused.
Anything simpler than basic type like a float, integer, or pointer that you want to return you need to use malloc to allocate heap memory. That memory will remain allocated until it is freed or the program exits.
It's a good idea to put your struct allocation and freeing into a function for DRY purposes and to isolate it from the rest of the code. While it's simple now, struct allocation is often complicated.
struct node *node_new {
return malloc(sizeof(struct node));
}
void link_list_add_ele(link_list * list, void * ele){
struct node *eleNode = node_new();
eleNode->value = ele;
eleNode->next = NULL;
link_list_add(list, eleNode);
}
And when you delete a node you must free the memory.
void node_free(struct node *node) {
free(node);
}
What you have been observing is right. The Linked List nodes should be allocated dynamically (i.e, using functions like malloc, calloc or realloc) if you want to use the Linked List beyond the scope of the function in which you have created it. You need to free the dynamically allocated memory once they are not needed. If you don't do that, then you will have memory leaks.
To test the code, I added 5 different integers and that struct I made inside the method got the same memory address during all the 5 additions.
It is because you have been allocating the node over Stack memory and hence, it has automatic storage class (Learn more about Storage Classes). The memory location allocated to that node will destroyed when you exit from your function link_list_add_ele. It is no longer valid once the wrapper function returns.
One more point:
You have been passing wrong parameters to link_list_add. The second parameter is a pointer but you have been passing it a value.
One important remark:
Try to understand various Warnings and Errors thrown by your compiler.
In my Linux, I try to compile my code with various verbose warning flags.
gcc example.c -o example -Wall -Wextra -Wshadow
If you are using an IDE, then there will be some settings options to enable warning.
I compiled your code with gcc filename.c -Wall and it gave me this error:
error: incompatible type for argument 2 of ‘link_list_add’
link_list_add(list, eleNode);
^~~~~~~
note: expected ‘struct node *’ but argument is of type ‘struct node’
void link_list_add(link_list * list, struct node * ele) {
I have edited your function to remove the Warnings and allocated the memory over heap:
#include <stdio.h>
#include <stdlib.h>
void link_list_add_ele(link_list *list, void *ele)
{
struct node *eleNode = malloc(sizeof(struct node)); // this gives the same address every single time.
eleNode->value = ele;
eleNode->next = NULL;
link_list_add(list, eleNode);
}
You also need to include the header file #include <stdlib.h> and don't forget to free the memory once it is not needed as C doesn't have automatic garbage collection and hence, you may observe memory leaks if you don't free them properly.
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;
}
}
My question is an extension of this: Returning pointer to a local structure
I wrote the following code to create an empty list:
struct node* create_empty_list(void)
{
struct node *head = NULL;
return head;
}
I just read that returning pointers to local variables is useless, since the variable will be destroyed when the function exits. I believe the above code is returning a NULL pointer, so I don't think it's a pointer to a local variable.
Where is the memory allocated to the pointer in this case. I didn't allocate any memory on the heap, and it should be on the stack, as an automatic variable. But what happens when the code exits (to the pointer), if I try to use it in the program, by assigning this pointer some pointees / de-referencing and alike?
struct node* create_empty_list(void)
{
struct node *head = NULL;
return head;
}
is equivalent to:
struct node* create_empty_list(void)
{
return NULL;
}
which is perfectly fine.
The problem would happen if you had something like:
struct node head;
return &head; // BAD, returning a pointer to an automatic object
Here, you are returning the value of a local variable, which is OK:
struct node* create_empty_list()
{
struct node* head = NULL;
return head;
}
The value of head, which happens to be NULL (0), is copied into the stack before function create_empty_list returns. The calling function would typically copy this value into some other variable.
For example:
void some_func()
{
struct node* some_var = create_empty_list();
...
}
In each of the examples below, you would be returning the address of a local variable, which is not OK:
struct node* create_empty_list()
{
struct node head = ...;
return &head;
}
struct node** create_empty_list()
{
struct node* head = ...;
return &head;
}
The address of head, which may be a different address every time function create_empty_list is called (depending on the state of the stack at that point), is returned. This address, which is typically a 4-byte value or an 8-byte value (depending on your system's address space), is copied into the stack before the function returns. You may use this value "in any way you like", but you should not rely on the fact that it represents the memory address of a valid variable.
A few basic facts about variables, that are important for you to understand:
Every variable has an address and a value.
The address of a variable is constant (i.e., it cannot change after you declare the variable).
The value of a variable is not constant (unless you explicitly declare it as a const variable).
With the word pointer being used, it is implied that the value of the variable is by itself the address of some other variable. Nonetheless, the pointer still has its own address (which is unrelated to its value).
Please note that the description above does not apply for arrays.
As others have mentioned, you are returning value, what is perfectly fine.
However, if you had changed functions body to:
struct node head;
return &head;
you would return address (pointer to) local variable and that could be potentially dangerous as it is allocated on the stack and freed immediately after leaving function body.
If you changed your code to:
struct node * head = (struct node *) malloc( sizeof( struct node ) );;
return head;
Then you are returning value of local value, that is pointer to heap-allocated memory which will remain valid until you call free on it.
Answering
Where is the memory allocated to the pointer in this case. I didn't
allocate any memory on the heap, and it should be on the stack, as an
automatic variable. But what happens when the code exits (to the
pointer), if I try to use it in the program, by assigning this pointer
some pointees / de-referencing and alike?
There is no memory allocated to the pointer in your case. There is memory allocated to contain the pointer, which is on the stack, but since it is pointing to NULL it doesn't point to any usable memory. Also, you shouldn't worry about that your pointer is on the stack, because returning it would create a copy of the pointer.
(As others mentioned) memory is allocated on the stack implicitly when you declare objects in a function body. As you probably know (judging by your question), memory is allocated on the heap by explicitly requesting so (using malloc in C).
If you try to dereference your pointer you are going to get a segmentation fault. You can assign to it, as this would just overwrite the NULL value. To make sure you don't get a segmentation fault, you need to check that the list that you are using is not the NULL pointer. For example here is an append function:
struct node
{
int elem;
struct node* next;
};
struct node* append(struct node* list, int el) {
// save the head of the list, as we would be modifying the "list" var
struct node* res = list;
// create a single element (could be a separate function)
struct node* nn = (struct node*)malloc(sizeof(struct node));
nn->elem = el;
nn->next = NULL;
// if the given list is not empty
if (NULL != list) {
// find the end of the list
while (NULL != list->next) list = list->next;
// append the new element
list->next = nn;
} else {
// if the given list is empty, just return the new element
res = nn;
}
return res;
}
The crucial part is the if (NULL != list) check. Without it, you would try to dereference list, and thus get a segmentation fault.
I have a simple Linked List node as follows
typedef struct node {
void *data;
struct ListElement *next;
} node;
Also I have a node create and delete function as follows:
void createNode(void *data){
node *n = malloc(sizeof(node));
//assign data to data and initialize pointer to NULL
}
void deleteNode(List *list, Node *node){
//Take care of the next pointer
free(node);
}
When I free the node, do I have to delete the members of the struct (data and next pointer) as well? Since I am not using malloc specifically for the members, but only for the entire struct? If so then how do I do it? Will all the members of the node be placed on the heap, and the stack will not be used at all?
The ultimate rule: you free() exactly the same number of times you malloc() (or calloc(), or...)
So:
I. If the data points to something allocated by these functions, then yes, you need to do so.
II. node->next is to be freed of course (assuming you are freeing the entire list), so you need to free it anyway, but only after you have taken care of the next element.
An iterative solution:
void free_list(Node *list)
{
while (list != NULL) {
Node *p = list->next;
// maybe:
// free(list->data);
free(list);
list = p;
}
}
A recursive solution:
void free_list(Node *list)
{
if (list->next != NULL) {
free_list(list->next);
}
// free(list->data);
free(list);
}
Usually, you will need to also free the data member, and you have to do that before freeing node,
free(node->data);
free(node);
but you don't need to free node->next, since either you want to keep the remainder of the list, or you free the entire list, and then freeing the next is done in the next iteration of the loop.
You must not free node->data if that doesn't point to allocated (with malloc or the like) memory, but that is a rare situation.
data is not a variable, it's a member of struct node. If you dynamically allocate struct node with a call to malloc(), you get a chunk of memory large enough to hold all the members of the struct. This obviously includes the storage for the data pointer, but not for the contents the pointer points to. Consequently, the storage for struct members must not be freed separately, it is enough to free the struct.
However, since data is itself a pointer, there is no telling where the memory it points to and whether this memory needs to be freed until we see how it is initialized.
I'm writing a bit of code for a class, but since I have no experience in C I'm a bit unsure of what the code I've written actually does. Particularly what the memory looks like. Here's the relevant bits:
typedef struct listnode *Node;
typedef struct listnode {
void *data;
Node next;
Node previous;
} Listnode;
typedef struct listhead *LIST;
typedef struct listhead {
int size;
Node first;
Node last;
Node current;
} Listhead;
#define HALLOCSIZE 50
static LIST hallocbuf[HALLOCSIZE];
static LIST *hallocp = hallocbuf;
LIST *CreateList()
{
if(hallocbuf + HALLOCSIZE - hallocp >= 1)
{
LIST temp;
temp->size = 0;
temp->first = NULL;
temp->last = NULL;
temp->current = NULL;
*hallocp = temp;
return hallocp;
}else
return NULL;
}
So my question is, in the CreateList function, how is the program allocating memory for temp? And does the code *hallocp = temp copy the temp LIST into the hallocbuf array? I am trying to have all my LIST structs sit in the allocated memory for hallocbuf. Is this what I'm doing? I'm a bit uncertain of how the typedef, structs and pointers play together.
Thanks!
So my question is, in the CreateList function, how is the program allocating memory for temp?
It isn't, which is a problem. It should do something like this:
temp = malloc(sizeof(Listhead));
And does the code *hallocp = temp copy the temp LIST into the hallocbuf array?
It copies the pointer that was saved in temp into the first element of hallocbuf (assuming that hallocp hasn't been changed anywhere and still has the value that it has been initialized to, pointing to hallocbuf[0]).
Generally it's not usually a good idea to hide the fact that LIST and Node are pointers behind typedefs. It's much clearer where memory needs to be allocated of freed if it's obvious which variables are pointer, and having an explicit * in the variable declaration makes that clear.
temp is allocated in the space used for objects with "automatic storage duration" - this is usually on a runtime stack, but you don't really need to know the details. The space is deallocated when the block in which it was allocated is exited (in your case, when you hit the return).
The line *hallocp = temp; does indeed copy the value of temp into the memory that hallocp is pointing at, which is hallocbuf[0].
The problem is that temp is just a pointer itself - and it's not pointing at anything. This is called a "dangling pointer". This means that when you try to access what it's pointing at, you have an error. That happens in these lines:
temp->size = 0;
temp->first = NULL;
temp->last = NULL;
temp->current = NULL;
You can't have your structs sit in the memory allocated for hallocbuf, because it doesn't have room for structs - it's just an array of pointers, not an array of structs.
If LIST were
typedef struct listhead LIST;
and you accessed temp
temp.size = 0;
...
then
*hallocp++ = temp;
would use hallocp as a pointer into the hallocbuf buffer and place the newly initialized element there. Not the best way to do it, though. You could replace temp with
hallocp->size = 0;
...
++hallocp;