Feel free to edit the title if it doesn't make sense. So I've been using malloc for a while without really being completely sure of how it works. If I create an int pointer and set it equal to malloc(10*sizeof(int), I figure that it allocates a block in memory of 10 times the size of one int, then returns the starting address of this allocation, but nothing is actually initialized within that memory yet. Am I OK so far?
Now say I create a struct for linked list nodes like this:
typedef struct node_ {
int data;
struct node_ *next;
} Node;
and then have a create linked list function:
Node* LLCreate(int data) {
Node *head = malloc(sizeof(Node));
if ( head != NULL) {
head->next = NULL; // don't get how malloc created `next`
head->data = data; // or `data`
}
return head;
}
What I don't get, and can't seem to google appropriately, is, if head is just the starting location in memory of an empty block of size Node, and not an actual variable, how does it have the local variables of next and data?
Maybe this is a nonsensical question because I have some fundamental misunderstanding of what's going on here, but if anyone understands what I'm trying to ask and could clear this up for me I'd really appreciate it.
It doesnt have local variables like next and data.
next and data are just used to calculate the address relative to from where node is pointing.
When you do node->data then the address is calculated as address pointed by node + (total bytes required by any metadata for malloc) + 0 because data is the first member of node struct.
And when you do node->next then the address is calculated as address pointed by node + (total bytes required by any metadata for malloc) + sizeof(data) , because next is the second member of the node struct that comes after data member.
Related
I created a structure for a linked list node in C as follows.
struct node
{
int data;
struct node *next;
} *START = NULL;
Then when I need to access the properties of the structure, I create a pointer to structure as follows.
struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;
I want to know if we can use
struct node node1
instead of the current declaration and what changes would that make in the program.
Also, I want to know why *START=NULL is outside the structure and what its data type is ?
You need to allocate the memory for the struct. Here you have a simple function which appends the node to the end of the list
struct node
{
int data;
struct node *next;
} *START = NULL;
struct node *append(int data)
{
struct node *node1 = malloc(sizeof(*node1));
struct node *list = START;
if(node1)
{
node1 -> data = data;
node1 -> next = NULL;
if(list)
{
while(list -> next)
{
list = list -> next;
}
list -> next = node1;
}
else
{
START = node1;
}
}
return node1;
}
START is the variable of type pointer to the struct node.
struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;
First, the above code doesn't initialize node1 to a valid memory address. It merely creates a pointer called node1 which can take the address of a variable of struct node type which hasn't been properly initialized.
You need to change the code to the following.
struct node *node1 = (struct node*)malloc(sizeof(struct node));
node1 -> data = 12;
node1 -> next = NULL;
The above will allocate memory for struct node type and initialize node1 with the address of the allocated memory.
Now let's get to your questions.
I want to know if we can use
struct node node1
instead of the current declaration and what changes would that make in the program.
You can use the above declaration in your program, but it will create node1 on stack rather than on heap. Probably this is not the behaviour you want since the variable made on stack has the lifetime of the scope in which it's created. In your case I assume you want to create a linked list (or similar structure), therefore you need the list to be accessible even after the function in which the appending happens returns.
Anyway, if you created the variable on stack you can simply use . operator to access structure members.
struct node node1;
node1.data = 12;
node1.next = NULL;
Also, I want to know why *START=NULL is outside the structure and what
its data type is?
It simply defines a pointer variable named START that can point to struct node and initialize it with NULL.
[...] when I need to access the properties of the structure, I create
a pointer to structure as follows.
struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;
Not exactly. You have declared node1 as a variable of type struct node *, but you have not created a pointer, in the sense that you have not given that variable a value that points to any structure. Subsequently attempting to access a struct node via that variable's (indeterminate) value therefore produces undefined behavior. Among the more likely outcomes are that your program crashes or that unexpected changes are made to random objects in its memory.
To be able to use node1 to access a struct node as you show, you first need to assign it to point to one (or at least to memory that can be made to contain one). You can do that either by assigning it the address of an existing struct node or by allocating memory sufficient for a struct node and assigning its address to node1. More on those alternatives later.
I want to know if we can use
struct node node1
instead of the current declaration and what changes would that make in
the program.
You definitely can declare node1 as a struct node instead of as a pointer to one. In the scope of such a declaration, you would access its members via the direct member-access operator (.) instead of via the indirect one (->):
node1.data = 12;
node1.next = NULL;
Furthermore, one of the ways to obtain a pointer to a struct node would be to use the address-of operator (&) to obtain that structure's address:
struct node *node_ptr = &node1;
HOWEVER, the lifetime of the node1 object declared that way ends when control passes out of the innermost block in which the declaration appears (if any), any pointers to it notwithstanding. As such, that usually is not what you want for a linked-list node.
For linked-list applications (among others), one generally wants an object whose lifetime doesn't end until you say it should do, and that can be achieved by dynamically allocating memory for the structure. For example,
struct node *node_ptr = malloc(sizeof(*node_ptr));
The allocated memory remains allocated until you explicitly free() it, whether in that scope or in another. Either way, to access the structure members through a valid pointer, one uses the indirect access operator, as in your example:
node_ptr->data = 42;
node_ptr->next = NULL;
or, equivalently, one first dereferences the pointer and then uses the direct member access operator:
(*node_ptr).data = 42;
(*node_ptr).next = NULL;
.
Also, I want to know why *START=NULL is outside the structure and what
its data type is ?
You said that you wrote the code. If you don't know the significance of the *START=NULL part, then what is it doing in your code?
In any event, it is analogous to the *node_ptr = &node1 above. START is declared (at file scope) as a pointer to a struct node, and its initial (pointer) value is assigned to be NULL, which explicitly and testably does not point to any structure.
When do we use structure variable and structure pointer?
Depends on the use case. When you create a structure variable you actually allocate the structure object on the stack. When you use pointer you usally allocate the structure object in heap memory and point to this object via the pointer.
You can resize and deallocate the dynamically allocated structure object whenever you want to, while the static can't be changes in size and it is only destroyed once the scope of it ends (in case of an automatic structure variable).
More details to the difference between static vs. dynamic allocation you can find in the links below the answer.
Which way you choose, depends on what you want to do and how you want to do it.
I want to know if we can use struct node node1 instead of the current declaration and what changes would that make in the program.
That would make node1 a variable of the structure itself; it would not be a pointer to an object of the structure only anymore.
Beside the things mentioned above and others, the access to the members would be different:
node1 . data = 12;
node1 . next = NULL;
Also I want to know why *START=NULL is outside the structure and what it's data type is.
START is of type struct node * (a pointer to struct node) and initialized to NULL. It's definition is outside because it isn't a member, it is a pointer to an object of the structure.
Note that you need to assign a pointer to struct node to point to an object of struct node, but that is not what you did at:
struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;
So, this would invoke undefined behavior.
Allocate memory for the structure:
struct node *node1 = calloc (1, sizeof(*node1));
if (!node1)
{
fputs("Failure at memory allocation for node1!", stderr);
return EXIT_FAILURE;
}
node1 -> data = 12;
node1 -> next = NULL;
Related regarding point 1.:
What and where are the stack and heap?
Stack variables vs. Heap variables
Why would you ever want to allocate memory on the heap rather than the stack?
Which is faster: Stack allocation or Heap allocation
I am trying to understand the pointer logic behind prepending.
I declared a struct as follows:
typedef struct myList{
int info;
struct myList *link; //self referential structure;
} Node;
For memory allocation in the heap memory segment, I use the following function:
Node *getNode(){
return ((Node *)malloc(sizeof(Node)));
}
In the main function, I allocate memory for the first node, I assign its link to NULL and its value to 2.
Node *head = getNode();
head -> link = NULL;
head -> info = 2;
Then comes the prepend function:
void prepend(Node **headPointer, int value) {
Node *new_node;
new_node = getNode();
new_node -> info = value;
new_node -> link = *headPointer;
*headPointer = new_node;
}
I am using the following function call:
prepend(&head, 5)
As you can see, I'm using a pointer to a pointer. I store the address of head in headPointer. I create new_node and allocate memory to it. I assign its info field, then the link field gets the dereferenced headPointer, which is the value stored in head, which is in turn the address for the chunk of memory in the Heap segment.
So, I basically link new_node to head, right? Now comes the confusing part, for me. The dereferenced headPointer, which is head's pointed chunk of memory in the Heap segment, gets the value stored in new_node which is another address from the Heap segment, I guess. Then, both new_node and headPointer go out of scope. (?)
How does this all add up? Is there a simpler way to describe the situation or implement prepending?
Then, both new_node and headPointer go out of scope. (?)
At the end of the prepend() newnode goes out of scope but not the memory allocated since it is allocated on heap.If it were something like int a, then at the end of prepend(), a is gone out of scope and referencing a after that would be undefined behavior.Please read this and this to know about heap.
Also since you pass head of the list as pointer to pointer, when you change what the headPointer points to inside prepend(), it is reflected outside the function so you still have a pointer to the head of the list.
|2|-->NULL
^
|
head
After call to prepend()
1) |5|--> |2|-->NULL
^
|
head
2) |5|----> |2|--->NULL
^
|
head
Also remeber to have some way of accessing the heap allocated memory in order to deallocate it.If you don't have any means of pointing to a memory allocating on a heap, then you are left with a memory leak.
I have a type node whose pointer is being used in another struct as shown below.
typedef struct element {
void* data;
struct element *next;
} node;
typedef struct queue {
node *tail;
node *head;
int num_items;
} queue_t;
I create an empty queue using the following code, but I am not sure if head and tail should be set to NULL since temp is not pointing anywhere yet.
queue_t *temp;
temp = malloc(sizeof(queue_t));
if (temp == NULL){
return NULL;
}
temp->head = NULL;
temp->tail = NULL;
temp->num_items = 0;
As per my understanding, malloc will only make temp point to some address space whose size is equal to the size of the struct queue_t. The address space does not contain a valid queue element yet. So how are temp->head = NULL; and temp->tail = NULL; valid statements?
Can someone please explain why this works?
The address space does not contain a valid queue element yet.
Correct, the allocated memory only contains a queue_t
So how are temp->head = NULL; and temp->tail = NULL; valid statements?
head and tail are not part of struct element. head and tail are part of queue_t. You have allocated a queue_t so it is OK to assign values to head and tail. In this case you assign the NULL value to show that they don't point to anything valid yet.
When you allocate a node (aka struct element) you update head and tail like:
// Add first node
temp->head == malloc(sizeof(node));
temp->tail == temp->head;
if (temp->head == NULL){
return NULL;
}
temp->num_items = 1;
// Initialize the new node
temp->head->next = NULL;
temp->head->data = NULL;
// Note: Adding more node requires more complex code
What is the definition of a "valid queue element"? If it's "sufficient space to hold a queue element and where the locations that hold the head and tail pointers have valid values", then setting them, to NULL makes it valid. If it's not that, what is it?
As per my understanding, malloc will only make temp point to some
address space whose size is equal to the size of the struct queue_t.
Correct.
The address space does not contain a valid queue element yet.
Not sure what you what you meant by "valid", but that statement is also correct.
So how are temp->head = NULL; and temp->tail = NULL; valid statements?
It is precisely those statements that makes your allocated space a valid queue element!
Can someone please explain why this works?
Your question fundamentally is no different from a statement such as int i;. Your implementation sets aside a space to hold an integer. However, it is as yet invalid because you have not given it any (meaningful) value. Once you set i = 0; or i = 42;, the space that you call i is now a valid integer.
Hope that helps.
As per my understanding, malloc will only make temp point to some address space whose size is equal to the size of the struct queue_t.
The malloc function call returns an address to the beginning of the allocated memory of size specified in the argument of malloc function call(in bytes). The allocated memory space will be of size specified in the argument of the malloc. However, the address returned by malloc will be the beginning of that memory space. Therefore, you can access upto the size of the memory space safely using the pointer to that memory space.
The address space does not contain a valid queue element yet.
The C Standard library has allocated a valid memory space for your pointer variable temp to point to. However, the values stored at that memory space could be garbage. Therefore, the pointer to node and num_items data members which have some valid memory space allocated to them within your queue_t may have garbage value. For example, after allocating the memory for queue_t, you can try to print the value of num_items using printf function.
queue_t *temp = malloc(sizeof(queue_t));
if (temp == NULL){
return NULL;
}
printf("The value of num_items: %d\n", temp->num_items);
The above example may print any garbage value. Since, C language doesn't have constructors to initialize newly created variables, you should initialize every variable you create with some stable value.
You can also use calloc function call which also sets allocated memory to zero after allocating the memory space.
So how are temp->head = NULL; and temp->tail = NULL; valid statements?
The memory is allocated by malloc which may contain any garbage value. The data members of queue_t share that memory space. Since, memory space can have garbage data, the data members will be having any random garbage data. That's why it is a good approach to initialize data members of the struct allocated by malloc to some stable values. That's what you have done in your program.
Actually, temp's data members head and tail should point to the addresses of variables of type node. The malloc call has allocated the pointer variables. These pointer variables can point to any variable of type node (or store the address of variable of type node). But you haven't allocated any node variable yet and you don't want to create dangling pointer. Therefore, you should initialize these pointer variables with NULL.
Your program should look like this:
queue_t *temp;
temp = malloc(sizeof(queue_t));
if (temp == NULL){
return NULL;
}
temp->head = NULL;
temp->tail = NULL;
temp->num_items = 0;
//Allocate some node
node *n = malloc(sizeof(node));
int data = 1;
n->data=&data;
n->next=NULL;
temp->head=n;
temp->tail=n;
temp->num_items=1;
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;
}
}
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);