I am trying to dynamically allocate list of pointers to pointers of structs which each contain a list of structs with the following definition:
struct node {
char *text;
struct node *next; };
I am also using a typedef:
typedef struct node Node;
I am creating a list of nodes to hold each list by declaring the following:
Node **list;
list = (struct node**) malloc(sizeof(struct node*) * arraySize);
At each of the nodes of list I will have another list which I am creating as follows:
list[i] = malloc(sizeof(struct node*) * subArraySize);
I have several questions:
Is this the correct implementation for such a problem?
How can I access the text data member of the first node of each list within the larger list?
If my question is vague please let me know. My confusion on this topic makes it difficult to word my question properly.
Assuming your memory is allocated and filled up correctly, you'd access the text data member of the first node of each node* array within the larger node** array via:
list[i]->text
But, to answer your question about the implementation being correct, it's not really. You'd probably be happier doing this:
struct node **list;
list = (struct node**) calloc(sizeof(struct node*) * arraySize);
for (int i=0; i<arraySize; ++i) {
list[i] = (struct node*) malloc(sizeof(struct node));
list[i]->text = ""; // or whatever you want to start with
list[i]->next = NULL;
}
This creates a node** array (called list, since you wanted to call it that, but I would call it something else indicates it's an array of node-based linked lists), then instantiates a block of memory for each head node so that list is full of valid node*s and you can start working with them.
When you go to append something to each of your linked lists, you'd do something like this (this appends to the end, it's up to you to implement insertion based on comparing values if you want sorted data, etc.):
int i = index_where_you_want_to_insert;
struct node *currNode = list[i];
struct node *newNode = (struct node*) malloc(sizeof(struct node));
newNode->text = ""; // or whatever you want to start with
newNode->next = NULL;
while(currNode->next != NULL) {
currNode = currNode->next;
}
currNode->next = newNode;
It may also help you to see this question about using typedef with linked lists.
If I've made any syntactic or semantic errors in my code, I apologize, it's been a while since I wrote C and I may be rusty with how to refer to structs. I welcome corrections.
Related
All the implementations I have seen online use pointer to declare nodes and then will use malloc to create space for them like this:
struct Node
{
int data;
struct Node *next;
};
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
...
But I can also create the same without pointers and malloc like this:
struct node {
int id;
struct node* next;
};
struct node head = {0, NULL};
struct node one = {1, NULL};
struct node two = {2, NULL};
struct node tail = {3, NULL};
int main(){
head.next = &one;
one.next = &two;
two.next = &tail;
...
My question is, why the 1st method is mostly the one used, why do we need to declare each node as pointer and why do we need malloc?
(Just to point out I know why struct Node *next; is declared as pointer int the struct declaration).
You should do this with local variables, not global ones, but the general idea would be the same. You should also steer towards having arrays and not heaps of otherwise unrelated variables:
struct node {
int id;
struct node* next;
};
int main(){
struct node nodes[4];
for (int i = 0; i < 4; ++i) {
nodes[i].id = (3 - i);
if (i != 0) {
nodes[i].next = &nodes[i-1];
}
}
return 0;
}
Where something like that assembles them in reverse order for convenience, but they're all grouped together in terms of memory initially.
malloc is used because you often don't know how many you're going to have, or they get added and removed unpredictably. A general-purpose solution would allocate them as necessary. A specialized implementation might allocate them as a single block, but that's highly situational.
Here the lifespan of nodes is within that function alone, so as soon as that function ends the data goes away. In other words:
struct node* allocateNodes() {
struct node nodes[10];
return &nodes; // Returns a pointer to an out-of-scope variable, undefined behaviour
}
That won't work. You need a longer lived allocation which is precisely what malloc provides:
struct node* allocateNodes() {
struct node *nodes = calloc(10, sizeof(struct node));
return nodes; // Returns a pointer to an allocated structure, which is fine
}
The problem is if you malloc you are responsible for calling free to release the memory, so it becomes more work.
You'll see both styles used in code depending on the required lifespan of the variables in question.
If you know ahead of time exactly how many items will be in your list, then you're probably better off using an array rather than a list. The whole point of a linked list is to be able to grow to an unknown size at runtime, and that requires dynamic memory allocation (i.e., malloc).
Here is the code to create a link in the list which i read off the internet to try understand linked lists in c:
//insert link at first location
void insertFirst(int key, int data) {
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
//point it to old first node
link->next = head;
//point first to new first node
head = link;
}
I am really not understanding how the following line works as a whole:
struct node *link = (struct node*) malloc(sizeof(struct node));
and more specifically:
(struct node*)
because my understanding is that the asterisk must come before the pointer name and yet its at the end of the struct name. Please correct me if I'm wrong and please if you can, explain how this works?
Casting the return value of malloc is unnecessary.
As per standard 7.22.3.4
The malloc function returns either a null pointer or a pointer to the
allocated space.
You should check its return value to know whether it succeeded or not.
What malloc does?
The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.
my understanding is that the asterisk must come before the pointer name and yet its at the end of the struct name
Here you are not dereferencing anything. Rather you are typecasting. (which is again I would repeat that unnecessary).
struct node* here is a type of the pointer variable. Same way int or double is a type, this is also a type.
Assume you have to create database of a students having some entities.
struct node
{
int id;
char name [100];
};
Next thing,
struct node *link = (struct node*) malloc(sizeof(struct node));
How above line works ? you need to create one node or memory, So how will you create it, use malloc(). Next things how much memory you are going to create , equal to total size of your data members of structure, so for that its using
struct node *link = malloc(sizeof(struct node));
here link is nothing but name of dynamic memory we created to put some data into that. once memory is created put some data into memory.
scanf("%d %s\n",&link->id,link->name);
similarly you can do above task no of times.
typecasting is not compulsory or not advised to do. So below statement is correct.
struct node *link = malloc(sizeof(struct node));
In order to create a linked list you have to allocate the units -in your case :
struct node
so either you pre-allocate the memory for the list or dynamically allocate them every time you add a node to the list, the memoery for the node has to be recruited from somewhere, in this case - malloc does that.
Hope that helps
I'm studying linked lists from this article.
The writer of the tutorial never creates actual nodes, but only pointer variables of type node, as you can see with the following code...
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
and then he allocates space for them in the heap...
head = (struct node*)malloc(sizeof(struct node));
second = (struct node*)malloc(sizeof(struct node));
third = (struct node*)malloc(sizeof(struct node));
why doesn't he ever create actual nodes? code for which should look something like this...
struct node head;
struct node second;
struct node third;
If my knowledge is right (correct me if I'm wrong). Simply declaring the pointer variable doesn't create the actual variable(node in case of linked lists), and hence cannot be dereferenced like the writer of the tutorial in the article using the code
head->data = 1;
I mean, if that works, then why doesn't this work?
int *a;
a=5;
printf("%d",*a);
Obviously, the above code doesn't output 5.
Which means that another variable needs to be created, and then it needs to be stated that the address of the variable is stored in a pointer variable, only then it can be dereferenced...like the following code...
int *a;
int b=5;
a=&b;
printf("%d",*a);
This outputs 5.
So how does the author gets away with not creating the nodes? He simply creates the pointer variables and then simply dereferences them....
The nodes are in the heap, that's what malloc is for.
To use code without linked list to explain, it's similar to:
int *a = NULL;
a = malloc(sizeof(int));
*a = 5;
printf("%d",*a);
The structure pointers are created so that they can refer to address.Since normal structure variables can't store the address, this syntax is wrong.
struct node head;
struct node second;
struct node third;
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.)
As part of an assignment that is now past due, I was to read a list of search terms from a text file and store these in memory for searching. I decided to use a linked list to store the terms and my implemenation of struct node (stored in myheader.h) looks like this:
struct Node{
char * term;
int termLength;
struct Node *next;};
To save the rootNode as the head of my list, I had a separate function for creating it called startList that is defined as such:
struct Node * startList(char * sterm){
struct Node * rootNode;
rootNode=(struct Node *)malloc(sizeof(struct Node));
assert(rootNode != NULL);
memset(rootNode,0,sizeof(struct Node));
rootNode->term=sterm;
rootNode->termLength = strlen(sterm);
rootNode->next=NULL;
return rootNode;
}
This seems to work fine, the trouble arises when I try to add a new node onto this rootNode, which is supposed to be done with this function:
void insert_another_node( struct Node * headNode, char * sterm){
struct Node * newNode = (struct Node *) malloc(sizeof(struct Node));
newNode->term=sterm;
newNode->next=NULL;
newNode->termLength=strlen(sterm);
while (headNode->next != NULL){
headNode=headNode->next;}
headNode->next=newNode;
}
These functions are all called in this for loop:
while ((fgets(search_wrd,41,list)) != NULL){
strtok(search_wrd, "\n");
if (count==0){
rootNode=startList(search_wrd);}
else{
insert_another_node(rootNode,search_wrd);}
count++;
}
fclose(list);
}
Say I am trying to store a list of planets in this list, the last planet being Neptune. The insert_another_node function will update the terms stored in ALL of the nodes to the most recent term (including the rootNode). The result is the right number of nodes, but they all store "Neptune" at someNode->term.
All of the insert to the end of a linked list implementations I've seen for a linked list in c follow my logic, so I can't understand how this weird update is happening let alone a way to fix it. Any help would be greatly appreciated!
You are just assigning sterm each time, all the assignments point to the same original buffer. You need to make a copy each time.
Use strdup like this:
rootNode->term=strdup(sterm)
and
newNode->term= strdup(sterm);
You need to allocate new memory for each sterm. If you reuse the same memory location they will all have the same value and if you change one you will change them all (because they are the same).