Hi I'm new to C and I'm struggling to get a linked list working I'm having to use global variables because I can't change the parameters of the function that is being called. I declare the struct and two global pointers to keep track of the root address and last address like this.
struct node {
char* pointer;
struct node *next;
};
struct node** rootNode;
struct node** lastNode;
Then inside the function I malloc a new struct and try to setup the first node in the list. To try and save the location of this node I think I'm assigning the global pointer lastNode to the pointer of root.
struct node *root = malloc(sizeof(struct node));
...
root->pointer=ptr;
root->next = 0;
rootNode = &root;
lastNode = &root;
Then I try to add aditional nodes by mallocing another node and then linking the previous node using the address stored in my lastNode pointer.
struct node *newNode = malloc(sizeof(struct node));
newNode->pointer=ptr ;
(*lastNode)->next = newNode;
newNode->next = 0;
lastNode = &newNode;
However this doesn't really seem to work. When I run the following the program matches the first two items in the list but then returns null for all nodes after that. I've been stuck on this for 2 days now and any help would really be appreciated :)
struct node* test;
test = (*rootNode);
enter code here
while (test) {
if (test->pointer == ptr) {
printf("MATCH!!");
notFound = 0;
break;
}
else {
test = test->next;
}
}
EDIT A couple of people have asked me to supply some more code. This is the function in which I would like to create the linked list. It's called multiple times while my program is running and I'm trying to add a new node to my linked list every time it gets called. I've also included the global variables at the top.
struct node** rootNode;
struct node** lastNode;
int firstRun = 1;
struct node {
char* pointer;
struct node *next;
};
void malloc(size_t sz) {
size_t maxSize = (size_t)-1;
char * payloadPtr = NULL;
if (sz > maxSize - sizeof(struct node)+sizeof(int)) {
return ptr;
}
if (firstRun) {
struct node *root = malloc(sizeof(struct node));
ptr = malloc(sizeof(size_t)+sz);
if (ptr == NULL) {
return ptr;
}
memcpy(ptr, &sz, sizeof(int));
payloadPtr = ptr+1;
root->pointer=payloadPtr;
root->next = 0;
rootNode = &root;
lastNode = &root;
firstRun = 0;
}
else {
struct node *newNode = malloc(sizeof(struct node));
ptr = malloc(sizeof(size_t)+sz);
if (ptr == NULL) {
return ptr;
}
memcpy(ptr, &sz, sizeof(int));
payloadPtr =ptr+1;
newNode->pointer= payloadPtr;
(*lastNode)->next = newNode;
newNode->next = 0;
lastNode = &newNode;
}
return payloadPtr;
}
There's a little clarification about changing the parameters into a function. In C you can only pass by pointers on function calls so if you want to modify the value of a struct node - you pass it like struct node * in the function. Similarly if you want to change the value of a struct node * in the function (as in allocate it or delete it) you may want to pass it like struct node **.
Your function prototype will probably have to look like this:
void addNode(struct node** root, char* value)
But you can also make that root node a local and also just a struct node * instead of struct node **. And then simply call it like:
addNode(&root, value);
Related
I am a beginner in data structure and I recently wrote a code to insert a new node at the beginning of a linked list using functions but when I run it the inserted node doesn't get printed, please help me verify the error in my code and correct it
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
void
traversal(struct Node *ptr)
{
while (ptr != NULL) {
printf("%d\n", ptr->data);
ptr = ptr->next;
}
}
void
insert_first(struct Node *head, int data)
{
struct Node *ptr = (struct Node *) malloc(sizeof(struct Node));
ptr->data = data;
ptr->next = head;
head = ptr;
}
int
main()
{
struct Node *head;
struct Node *second;
struct Node *third;
struct Node *fourth;
head = (struct Node *) malloc(sizeof(struct Node));
second = (struct Node *) malloc(sizeof(struct Node));
third = (struct Node *) malloc(sizeof(struct Node));
fourth = (struct Node *) malloc(sizeof(struct Node));
head->data = 10;
head->next = second;
second->data = 20;
second->next = third;
third->data = 30;
third->next = fourth;
fourth->data = 40;
fourth->next = NULL;
traversal(head);
insert_first(head, 0);
printf("\n");
traversal(head);
return 0;
}
insert_first() function parameter head is a local variable of insert_first() function. So, the statement head = ptr; will make changes in local variable only. These changes will not reflect in the pointer you have passed as first argument to insert_first() function.
As stated in one of the comments that you can return the updated value of head of list and assign that value to original head pointer of list.
Another way could be to pass the address of head pointer of list to insert_first() function (in case, if you want to keep the void as return type of insert_first() function).
For this, you have to changes the type of head parameter of insert_first() function from struct Node * to struct Node ** (double pointer) and pass the address of head (i.e. &head) to insert_first() function. Dereferencing head parameter of insert_first() function will give you the original pointer whose address you have passed and then you can make it point to some other address.
Implementation:
void
insert_first(struct Node **head, int data)
{
struct Node *ptr = (struct Node *) malloc(sizeof(struct Node));
ptr->data = data;
ptr->next = *head;
*head = ptr;
}
and call it like this
insert_first(&head, 0);
^^^
A suggestion:
Follow good programming practise - always check the malloc() return.
I have declared a global pointer ptr and want that it should point to current node during different function call.
This is a sample code where I am creating a new node in fun1 and inserting in link list. In func2 I want to update the other members of newNode in linklist with a different value.
Currently I am traversing the link list to get the current Node or last Node which I dont want since during insertion of new Records already we have to traverse to reach to last Node thus storing the address of last Node.
But by doing the below I am not getting the proper values. Kindly someone suggest where I went wrong.
I am doing like this :
#include<stdio.h>
#include <stdlib.h>
struct Node
{
int data1;
int data2;
struct Node* next;
};
struct Node* head=NULL;
struct Node* ptr =NULL; /* Global pointer */
void insertNode(struct Node ** , struct Node* );
void fun1();
void fun2();
void fun1()
{
struct Node* ptr1 =NULL;
ptr1 = (struct Node*)malloc(sizeof(struct Node*));
ptr1->data1=1; /* intilaizing with some values */
insertNode(&head,ptr1);
}
void fun2()
{
/* Updating the current Node in the linklist with new value . */
ptr->data2=2;
}
void insertNode(struct Node ** head, struct Node* NewRec)
{
if(*head ==NULL )
{
NewRec->next = *head;
*head = NewRec;
ptr=*head;
}
else
{
/* Locate the node before the point of insertion */
struct Node* current=NULL;
current = *head;
while (current->next!=NULL )
{
current = current->next;
}
NewRec->next = current->next;
current->next = NewRec;
ptr=current->next;
}
}
int main ()
{
fun1();
fun2();
while(head!=NULL)
{
printf("%d", head->data1);
printf("%d",head->data2);
head=head->next;
}
return 0;
}
You made a classic mistake.
This is wrong:
ptr1 = (struct Node*)malloc(sizeof(struct Node*));
The allocated space here is sizeof(struct Node*) which is the size of a pointer (usually 4 or 8 bytes depending on the platform). But you need to allocate space for the whole struct Node structure, whose size is sizeof(struct Node).
So you simply need this:
ptr1 = (struct Node*)malloc(sizeof(struct Node));
BTW: in C you don't cast the return value of malloc so you actually should write this:
ptr1 = malloc(sizeof(struct Node));
typedef struct LIST{
int count = 0;
}LIST;
typedef struct NODE{
int data;
struct NODE *link;
}NODE;
int main() {
NODE *p1, *p2, *p3;
p1 = (NODE*)malloc(sizeof(NODE));
p1->link = NULL;
p2 = (NODE*)malloc(sizeof(NODE));
p2->data = 20;
p2->link = NULL;
p1->link = p2;
I want to make add NODE function and list to control NODE.
Give me some answer to solve this problem.
you should define head in the list.
node * head;
Insert function as follows, to insert value in ascending order.
void insert(int val)
{
node * nd = new node();
nd->val = val;
if(head == NULL)
head = nd;
else
{
if(val <= head->val)
{
nd->next = head;
head = nd;
}
else
{
node * itr = head;
while(itr->next != NULL && itr->next->val <= val)
itr = itr->next;
nd->next = itr->next;
itr->next = nd;
}
}
}
First you probably want to add to your LIST struct a field "NODE *first", which points to NULL initially, and then will point to the first element of your list.
Then what does you add function should do? Add to the beginning or the end of the list?
If at the beginning: allocate a NODE, set its link pointer to the first element of your list and say that the first element of the list is now the node that you just allocated.
Try to give variable according to their work, so that it is easy to understand.
struct node
{
int val;
struct node* next;
};
void insert(struct node** head_ref, int data)
{
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->val = data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
int main()
{
struct node* head = NULL;
insert(&head,1);
insert(&head,2);
return 0;
}
Note that : Insert function will always add the value at front.
Try to write function for particular task.
I'll avoid giving you the entire answer in C code since it's in general better to "teach a man to fish".
I would suggest that you add a NODE * member to your LIST class to store the header node of your linked list.
The addNode that adds a node to the next node should look like this:
void addNode (LIST* list, NODE * penultNode, int newData);
// list: Address to the linked list info object
// penultNode: Address to the node after which you want to add a new node.
// Should be NULL if your linkedlist is empty
// newData: Data in the new node that you wanna add
Inside this function, your actions will depend on whether penultNode is NULL or not. If it is not null, your job is simple. You just allocate a new NODE object and set the pointer of penultNode->next to the new object. If it is NULL, that means that no node exists in the list yet. In this case, you will need to set the pointer of list->headerNode to the new NODE object.
My approach:
An array of fixed-length (lets say 20) each element is pointer to the first node of a linked list.
so i have 20 different linked list.
This is the structure:
struct node{
char data[16];
struct node *next;
};
My declaration for that array
struct node *nodesArr[20];
now to add a new node to one of the linked list, i do this:
struct node *temp;
temp = nodesArr[i]; // i is declared and its less than 20
addNode(temp,word); // word is declared (char *word) and has a value ("hello")
The addNode function:
void addNode(struct node *q, char *d){
if(q == NULL)
q = malloc(sizeof(struct node));
else{
while(q->next != NULL)
q = q->next;
q->next = malloc(sizeof(struct node));
q = q->next;
}
q->data = d; // this must done using strncpy
q->next = NULL;
}
and to print data from the array of linked list, i do this:
void print(){
int i;
struct node *temp;
for(i=0 ; i < 20; i++){
temp = nodesArr[i];
while(temp != NULL){
printf("%s\n",temp->data);
temp = temp->next;
}
}
}
now compiler gives no error, the program run and i pass the data to it, and when i call print it doesn't print any thing,,??
UPDATE::
after I edited the code (thx for you), i think the problem in the print function,, any idea ?
The problem lies in addNode(). When the list is empty you do:
q = malloc(sizeof(struct node));
but the scope of q is limited to addNode(). You should have declared addNode() as
void addNode(struct node **q, char *d)
and adjust your code accordingly:
*q = malloc(sizeof(struct node));
and so on...
When you pass struct node *q to addNode you are giving it an address for an element in your array. If you use malloc inside, then you are overwriting this variable q, which is local to the function and now points to something different, but you haven't changed your original array. Try using a pointer to pointer to node (struct node **q).
void addNode(struct node *q, char *d){
if(q == NULL)
q = malloc(sizeof(struct node));
Here's the problem.
The new value of q doesn't ever get out of the function, so your array of linked lists never gets updated.
Normally the solution here is to use a double-pointer:
void addNode(struct node **q, char *d){
if(*q == NULL)
*q = malloc(sizeof(struct node));
And call it like so:
addNode(&nodesArr[i],word);
Then, if you malloc a new node, the value in the array will be set to point to the new node.
struct node
{
int actual, estimated;
char c;
struct node *next;
} *head[4], *var[4], *trav[4];
void
insert_at_end (char c, int value, int value1)
{
struct node *temp;
temp = head[i];
var[i] = (struct node *) malloc (sizeof (struct node));
var[i]->actual = value;
//var1=(struct node *)malloc(sizeof(struct node));
var[i]->estimated = value1;
var[i]->c = c;
//printf("%d",var->estimated);
if (head[i] == NULL)
{
head[i] = var[i];
head[i]->next = NULL;
}
else
{
while (temp->next != NULL)
{
temp = temp->next;
}
var[i]->next = NULL;
temp->next = var[i];
}
}
I have created a List data structure implementation for generic data type with each node declared as following.
struct Node
{
void *data;
....
....
}
So each node in my list will have pointer to the actual data(generic could be anything) item that should be stored in the list.
I have following signature for adding a node to the list
AddNode(struct List *list, void* eledata);
the problem is when i want to remove a node i want to free even the data block pointed by *data pointer inside the node structure that is going to be freed. at first freeing of datablock seems to be straight forward
free(data) // forget about the syntax.....
But if data is pointing to a block created by malloc then the above call is fine....and we can free that block using free function
int *x = (int*) malloc(sizeof(int));
*x = 10;
AddNode(list,(void*)x); // x can be freed as it was created using malloc
what if a node is created as following
int x = 10;
AddNode(list,(void*)&x); // x cannot be freed as it was not created using malloc
Here we cannot call free on variable x!!!!
How do i know or implement the functionality for both dynamically allocated variables and static ones....that are passed to my list....
Thanks in advance...
The complete implementation is as following list.h simply contains function prototypes.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include "list.h"
//structure of each node
static struct Node{
void *Data;
struct Node * Next;
struct Node * Prev;
};
//complete list interface
struct List{
int Size;
struct Node DummyNode; //dummy node
void (*Print)(void *Data);
};
//create new List
struct List * CreateList(void(*Print)(void* Data)){
struct List *newList = (struct List *)malloc(sizeof(struct List));
if(newList != NULL){
newList->DummyNode.Data = NULL;
newList->DummyNode.Next = newList->DummyNode.Prev = &newList->DummyNode;
newList->Size = 0;
newList->Print = NULL;
if(Print != NULL) newList->Print = Print; // hook to user provided print function
return newList;
}
return NULL;
}
//Node *ptr point to one node before the actual node to be removed
static void _RemoveNode(struct List *list, struct Node *ptr)
{
struct Node *temp = ptr->Next; //catch hold of node that is to be removed
ptr->Next = temp->Next; // link previous node's next pointer with the temp node next pointer
temp->Next->Prev = ptr; // link next node's previous pointer with previous node pointer
temp->Prev = NULL; // unlink from previous node
temp->Next = NULL; // unlink from next node
free(temp->Data); // free the data ............ !!! need to mode generic before cleaning the resource
free(temp); // remove the node itself.
list->Size--;
}
void RemoveNodeAt(struct List *list,int nodeIndex)
{
if( list->Size > 0 && (nodeIndex >= 0 && nodeIndex < list->Size)){
int i=-1; // meaning we are at dummy node
struct Node *ptr = NULL;
for(ptr = &list->DummyNode ;i < nodeIndex - 1 ;i++) // traverse up to one node before the actual node
ptr = ptr->Next;
_RemoveNode(list,ptr);
}
}
//Node *ptr point to one node before the actual node to be removed
static void _AddNode(struct List *list, struct Node *ptr,void *data)
{
//create New Node
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
if(newNode != NULL){
newNode->Data = data;
//shift node at index to right
newNode->Next = ptr->Next;
newNode->Prev = ptr;
ptr->Next = newNode;
newNode->Next->Prev = newNode;
list->Size++;
}
}
void AddNodeAt(struct List *list,int nodeIndex,void *data)
{
//A node can be added just before head and just after tail.
if( nodeIndex >= 0 && nodeIndex <= list->Size){
int i=-1; // meaning we are at dummy node
struct Node *ptr = NULL;
for(ptr = &list->DummyNode ;i < nodeIndex - 1 ;i++) // traverse up to one node before the actual node
ptr = ptr->Next;
_AddNode(list,ptr,data);
}
}
void RemoveNode(struct List *list)
{
if(list->Size > 0){ //check if the list is not empty
struct Node * temp = list->DummyNode.Prev; //catch hold of last node
temp->Prev->Next = temp->Next; //establish previous node's next pointer to temp node next pointer
temp->Next->Prev = temp->Prev; //establish next node's previous pointer to temp node previous pointer
temp->Next = NULL; // unlink temp node from next node
temp->Prev = NULL; // unlink temp node from previous node
free(temp->Data); // free the data ............ !!! need to mode generic before cleaning the resource
free(temp); // remove the node itself.
list->Size--;
}
}
void AddNode(struct List *list,void *data)
{
struct Node *ptr = list->DummyNode.Prev;
//create New Node
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
if(newNode != NULL){
newNode->Data = data;
//shift node at index to right
newNode->Next = ptr->Next;
newNode->Prev = ptr;
ptr->Next = newNode;
newNode->Next->Prev = newNode;
list->Size++;
}
}
void DeleteAllNodes(struct List *list)
{
struct Node *ptr = &list->DummyNode;
while(list->Size > 0){
_RemoveNode(list,ptr);
ptr = ptr->Next;
}
}
void Display(struct List *list)
{
if(list->Print != NULL){ //If conusmer doesnot provide a print function just give up printing process.
int i=0;
struct Node *ptr = &list->DummyNode;
for(i = 0; i < list->Size; i++){
ptr = ptr->Next;
list->Print(ptr->Data); // let the consumer of the list data structure print the way he wants
}
}
}
// must be used before inserting automatic variables are passed in to the list
// because freeing a automatic variable with free function is a crime....!!!! *(~_~)*
// So i want you to create clones of the automatic variables and pass those variables.
// AddNode(list,Clone(&i,sizeof(i)));
void * Clone(void *data, int size)
{
void * clone = malloc(size);
memcpy(clone,data,size);
return clone;
}
Well, the typical rule of thumb is that the allocator of heap space shall always also be the one who frees it. Things always start to get messy when it is not well defined which program module 'owns' the allocation.
In your example a clean implementation of the list would never delete the data itself, or would create a copy of the data on insertion such that the data truly belongs to the list. For this, also the size of the data has to be passed.
A good compromise that avoids unnecessary copies may be that the list always frees the data itself but on insertion the user can choose that no copy occurs. For this, he could pass size values of 0 or -1 to indicate that no copy is needed, as the data is already on the heap and will not be managed (freed) by sombody else.
If you are using such snippet
int x = 10;
AddNode(list, (void *)&x);
inside another function, where x is declared auto variable on stack, the code may not behave as you would expect. The pointer is generated from stack address and it's not guaranteed to hold that value of x when the function returns. The pointer you saved in the list will now point to some other data on the stack frame.
For clean implementation of a generic list, you should use dynamically allocated memory or global data which is not stored on stack. Your code will work for global or static variables but not for automatic variables.
There is no automatic way to know whether a pointer can be freed or not. If the logic of your program does not make it obvious, you are going to need a helper variable:
struct Node
{
void *data;
int data_on_heap; // on heap, so should be freed
....
....
};
You'll need to modify your AddNode function to take that info:
int *x = (int*) malloc(sizeof(int));
*x = 10;
AddNode(list, x, 1); // x can be freed as it was created using malloc
int x2 = 10;
AddNode(list, &x2, 0);
And when you want to free it, you'll have to check:
if (n->data_on_heap)
free(n->data);
Modify the AddNode function to always make a copy of the data passed to it, and free the data when you want to delete the node.