Comparing a variable to a linked list's variable - c

I have a program where details are taken by a user for a survey. It contains details of a person with a pps as a unique identifier. When adding a newNode to the list and checking the PPS it does not recognise if the number is the same in any of the nodes. Adding a printf into the loop to show the current pps gives a nullptr exception. I have tried not using **head_ptr replacing with *head_ptr however this gives more errors down in the rest of the code where the node is added to the list.
//a new node is created which is filled with info. Some vaidation is done such as PPS number uniqueness and the node is added to the list
//in this function the node is added to the very front of the list. Note: the sorting does not happen here without sorting it would be a list of the most recently enetered items
//a second function will carry out the sort
void addSurvey(struct survey** head_ptr)
{
int inputPPS,inputAge,inputSmoker, inputDrink, inputExer, inputIncome;
int scanfBoolean;
struct survey *temp;
struct survey *newNode;
temp = *head_ptr;
newNode = (struct survey*)malloc(sizeof(struct survey));
printf("\nPlease enter your PPS number (Number must be unique)\n");
scanf("%d", &inputPPS);
while (temp != NULL)
{
if (inputPPS == temp->surveyDetails.ppsNo)
{
printf("\nPPS you have entered is not unique. \n\n");
free(newNode); free(temp);
return;
}
temp = temp->next;
printf("\nChecking list. PPS is %d\n\n", temp->surveyDetails.ppsNo);
}
newNode->surveyDetails.ppsNo = inputPPS;

You are freeing node once you found it
free(temp);
In this case after you return from this function addSurvey the pointer pointed to by struct survey** head_ptr points to freed memory and probably you use it incorrectly.
Even worse, when you assign new value to temp and you might have assigned a NULL to it, you are not checking this and you try to access pointer to that unknown memory to print integer:
temp = temp->next;
printf("\nChecking list. PPS is %d\n\n", temp->surveyDetails.ppsNo);

You do not link your new node (newNode) to the list leaving the list empty. You have to add
temp->next=newNode;
is an appropriate place

Related

Is there a way in C to create new nodes in a linked list without memory allocation?

I just learned the concept of a linked list in C, and tried implementing it. What I did was create a pointer head, and a pointer itr. To create a new node I would initialize a node normally (without using pointers), and then attach a pointer to it.
struct node temp; //A single node contains a value 'num' and a pointer to the next node.
temp.num=x;
temp.next=NULL;
if(head==NULL){
head=&temp;
}
else{
itr=head;
while(itr->next!=NULL){
itr=itr->next;
}
itr->next=&temp;
}
This method is not working, and based on my limited knowledge of pointers in C, I cannot figure out why. I know that the right way to do it is by using malloc to create new nodes, but I need to know why this method does not work.
Full Program:
#include <stdio.h>
struct node{
int num;
struct node *next;
};
int main(){
struct node *head=NULL;
struct node *itr;
struct node temp;
int choice;
printf("1. Enter new Node, 2. Traverse all nodes, 3. Exit.");
int x;
while(1){
printf("\nEnter your choice: ");
scanf("%d", &choice);
if(choice==1){
printf("Enter value: ");
scanf("%d", &x);
temp.num=x;
temp.next=NULL;
if(head==NULL){
head=&temp;
}
else{
itr=head;
while(itr->next!=NULL){
itr=itr->next;
}
itr->next=&temp;
}
}
else if(choice==2){
if(head==NULL){
printf("Empty List");
continue;
}
printf("The values are: ");
itr=head;
printf("%d ", itr->num);
while(itr->next!=NULL){
itr=itr->next;
printf("%d ", itr->num);
}
}
else{
break;
}
}
}
A linked list generally consists of several nodes, in which each node points to the next node in the list. The last node in the linked list should point to NULL to mark the end of the list.
However, you have only allocated memory for a single node. Therefore, you will only be able to store a single node in the linked list.
The code for adding the first node to the linked list is correct. However, the code for adding a second node cannot work, because you have not allocated any memory for the second node.
What your code for adding the second node is actually doing is overwriting the first node, and making this first node point to itself. That is why you are getting an infinite loop, if you attempt to print the linked list afterwards.
Therefore, I suggest that you instead use malloc for allocating memory for the nodes. That way, you won't be limited to a single node.
You must show your whole code.
I guess , in your case, if you define a function like this, the temp elem is funciton local variable, you need use malloc to make it accessable out of the function.
int addNode(struct node *head, inx x) {
struct node temp; //A single node contains a value 'num' and a pointer to the next node.
temp.num=x;
temp.next=NULL;
if(head==NULL){
head=&temp;
}
else{
itr=head;
while(itr->next!=NULL){
itr=itr->next;
}
itr->next=&temp;
}
}

Reverse the pointers in a linked list

Hello guys could you please help me in writing a procedure to reverse the pointers in a linked list . for example A->B->C->D would become A<-B<-C<-D without using extra linked list .
Edit:
------ okay guys so i have been looking for solution for this problem here is the code in case u want it :
void reverse_list(){
struct node *next, *current,*previous;
previous = NULL;
current =head;
while(current != NULL){
next = current->next;
current->next = previous;
previous=current;
current = next;
}
head = previous;
}
You could think of the list as a stack. Then you could easily reverse such a list by "popping" the nodes and "pushing" them into a new list.
The above could be done both destructively (destroying the old list) and non-destructively (creating the new list as a reversed copy of the original list).
As you didn't mention if you are implementing the linked list yourself or not.
So firstly I am assuming that you are doing it by yourself. So following is an implementation of linked list and again its pointers are reversed to make the link list reverse. You can take an idea from it.
#include<stdio.h>
#include<stdlib.h>//for using malloc
struct Node//Defining a structure for linked list's node
{
int info;//assuming it is an integer linked list
struct Node *link;//this pointer links a node to it's immediate neighbor node
};
struct Node *head=NULL,*temp;//some initializations and declarations
void insertion(int data)//To insert elements to linked list
{
struct Node *ptr;
ptr=malloc(sizeof(*ptr));//creating a new node for the newcomer
ptr->info=data;//taking the given integer value for the node to hold
//initializing with null as the current node may be the last node and
//if it is then it will point nobody
//...but if it is not when a new node comes in the future it will eventually be
//replaced to point the newcomer
ptr->link=NULL;
if(head==NULL)//head still null means we are creating the first node
{ //handling the head separately as it has no parent node
head=ptr;
temp=ptr;//copying the current node's pointer to temp such that we can
//find it as a parent of next node
}
else//for the rest of the nodes' creation
{
//as temp is the pointer to the previous node, so previous node is linking
//to its next node, i.e, the current node
temp->link=ptr;
//updating the temp to point the current node such that it can act as a parent node
//when the next node comes
temp=ptr;
}
}
void reversePointers()
{
struct Node *trav,*from=NULL,*temp;
for(trav=head;;)
{
if(trav->link==NULL)//if we have reached to the end
{
head=trav;//then the reverse linked list's head should point to the last element
trav->link=from;//and making the second last node as it's next node
break;
}
temp=trav;//saving current node pointer to update the "from" pointer
trav=trav->link;//advancing current node pointer to forward
temp->link=from;//making the current node to point to it's previous node
from=temp;//saving current node's pointer which will be used in next iteration
}
}
void traverse()//to traverse the nodes
{
struct Node *ptr=head;
while(ptr!=NULL)
{
printf("%d ",ptr->info);
ptr=ptr->link;
}
printf("\n");
}
int main(void)
{
int i,n,t;
printf("Enter Number of elements: ");
scanf("%d",&n);
printf("Enter Elements: ");
for(i=0;i<n;i++)
{
scanf("%d",&t);
insertion(t);
}
printf("Before reversing the pointers the elements are: ");
traverse();
//let's reverse the pointers to make the list to go backward
reversePointers();
printf("After reversing the pointers the elements are: ");
traverse();
}
Secondly if you are using STL list then the approach is quite straightforward. Just use,
your_list_name.reverse()
Again if you want to reverse the STL list just for iteration purpose then there is no need to actually reverse it. Instead you can use reverse iterator as following (say for an integer list):
for(list<int>::reverse_iterator it=your_list_name.rbegin();it!=your_list_name.rend();it++)
{
//do whatever you want
}

C: Learning to Code in C with pointers, Header files etc

I am trying to create a simple C program while learning about the concepts about pointers, linked list and header files.
I want to create a simple C program by clubbing all these concepts together for better understanding.
My code and its explanation is as follows:
I have a header file "header1.h " where I have declared the structure which is to be shared between various source files and also the "head" variable of the linked list.
The header file is as follows:
header1.h
struct node{
char * name;
struct node* next;
};
extern struct node* head;
Now, I have the main source-file named "start_prog.c" which has got the "main" function
and the menu which will control the execution of the of the program.
Menu has various options such as Add element ,Delete element , Reverse List etc (for simplicity I will only present two options here viz, Insert and Print list which are most important).
from the start_prog.c I call the "create" function which will add the element to the list.
If the list does not exist then it will create one else It will append the element to the list after the last element.
The create function is defined in another source file "create.c".
Both the files are as follows:
start_prog.c:
#include<stdio.h>
#include<stdlib.h>
#include "header1.h" //include the header file
struct node* head = NULL; //Define the external variable head to be null initially
struct node* create();
void main(void){
int option;
do{
printf("\nplease select the option : \n\t\t1)add element \n\t\t2)Print List\n");
scanf("\n%d",&option);
switch(option){
case 1:
head = create();
break;
case 2:
print_list();
break;
}
}while(option != 3);
}
and the create.c file is as follows:
#include<stdio.h>
#include<stdlib.h>
#include "header1.h"
//this function creates the linked list if the list is null or inserts the
//element at the end of the list.
struct node* create() {
if(head == NULL){
//create a new list and return head.
printf("\nhead is null\n");
struct node* newnode = (struct node*)malloc(sizeof(struct node));
char * new_name;
printf("\nplease enter the new name\n ");
scanf("%s\n", new_name);
newnode -> name = new_name;
newnode -> next = NULL;
head = newnode;
return head;
}
else if(head != NULL){
printf("\nhead is not null\n ");
struct node* newnode = (struct node*)malloc(sizeof(struct node));
char * new_name;
printf("\n Please Enter the new name \n");
scanf("%s\n", new_name);
newnode -> name = new_name;
newnode -> next = NULL;
struct node* ptr = NULL;
ptr = head;
while((ptr -> next) != NULL){
ptr = ptr -> next;
}
ptr -> next = newnode;
return head;
}
}
when I run all these programs together I get Garbage values in the head and Segmentation fault error. What is Wrong in my code. What is the thing that I am missing. I feel that I am close to understand the concepts but missing some important point due to which I am not
able to write the program properly. Please find the bug/error in my code and the fault in my understanding.
Thankyou!
Generally Segmentation fault occurs when you to try to access or assign value from/to memory which is not assigned to that process.
Normally check places where you are assigning values or retrieving it whether your the is assigned to it or not.
one think i saw was
char * new_name; // declaring the pointer
printf("\n Please Enter the new name \n");
scanf("%s\n", new_name);//reading the value from stdin to where pointer is pointing
when you declare the pointer its filled with garbage value. which may be out of range of your process assigned memory. and your asking your compiler to store the value there which is illegal hence the kernel raises a signal SIGSEGV and halts your process.
Assign memory before assigning the value
new_name = malloc(20); // how much ever you think is required
In your create.c file
char * new_name;
printf("\nplease enter the new name\n ");
scanf("%s\n", new_name);
How will that above code execute, Please try to use array to store name temporarily there.
if you want to use pointer there then you have to allocate memrory for that poiner too.
and dont use '\n' in the scanf like that or else, it will not stop even when you press enter key it will stop only when you press any non-white space charater,which would be awfull.

What more does the code need to delete a node from a linked list successfully?

I want to delete a given node from a linked list by the node's index number (serial number). So what I tried to do in my function is that, first I have taken the user input of the index number. Then I used two node type pointers temp and current. I started traversing the list with current and when the index number of the node matches with the user input, I tried to delete the node. So far it is correct. I am facing problem with the deletion logic. Here is the code I tried:
void delete_node(struct node **start,int index_no)
{
int counter=0;
struct node *temp, *current;
temp=(struct node *)malloc(sizeof(struct node));
current=(struct node *)malloc(sizeof(struct node));
current=*start;
while(current->next!=NULL)
{
counter++;
if(counter==index_no)
{
temp= current->next;
free(current);
/*I guess some code is missing here. Help me finding the logic.*/
}
else
{
printf("\n The index number is invalid!!");
}
}
}
The commented portion lacks the deletion logic.
Also, I have a feeling that this code is not space and time-efficient. If it is so, please suggest to a way to make it more compact.
Why are you allocating two nodes in the delete function, then leaking their memory? It seems they should be initialized to start or one of its successors.
You also need to update the next pointer in the previous element and potentially also the start (head) of the list if the removed element was the first (ie. index_no == 1).
You also have an off-by-one error where the final node can never be deleted, because only a node with a ->next pointer will be considered for deletion.
Suggested reading: A Tutorial on Pointers and Arrays in C.
Deleting from a linked list is actually:
find the pointer that points to us
(if found) make it point to our .next pointer instead
delete our node.
In order to change the pointer that points to us, we need a pointer to it: a pointer to pointer. Luckily the first argument already is a pointer to pointer, it presumably points to the head pointer that points to the first list item.
struct node
{
struct node *next;
int num;
} ;
void delete(struct node **pp, int num) {
struct node *del;
int counter;
for (counter=0; *pp; pp= &(*pp)->next) {
if(counter++ == num) break;
}
if (!*pp) { printf("Couldn't find the node(%d)\n", num); return; }
/* if we get here, *pp points to the pointer that points to our current node */
del = *pp;
*pp = del->next;
free(del);
}

Linked list appears backwards

I have a linked list that is coming out backwards. I appear to be adding elements to the back of the list, when I want to place them on the front.
My nodes appear as follows:
struct node{
int data;
struct node* next;};
Next I set the head and variables
int info,x,listLength;
struct node *head = NULL;
struct node *temp;
printf("How many nodes?\n");
scanf("%d",&listLength);
Now I prompt for a new entry in the list, and move along the nodes
for(x=1;x<=listLength;x++){
printf("Insert an X value for node %d\n",x);
scanf("%d",&info);
temp = (struct node*)malloc(sizeof(struct node));
temp->data = info;
temp->next = head;
head = temp;
}
Finally I output the results and free the memory space
while(temp!=NULL){
printf("WE GOT %d\n",temp->data);
temp = temp->next;
}
free(temp);
However, if I enter input for three nodes and enter 1,2 and then 3, the output is 3,2, then 1! How can I change this to make sure the nodes are being added to the right place?
Thanks in advance!
Your code is saying
temp->next = head;
head = temp;
So you are adding to the start of the list, not the end, so "reverse order" is correct.
To add to the end you either need to keep track of the last node you added (e.g. struct node tail), or you need to search from head through the next ptrs until next = null to find where to add the new node.
Also: why the free(temp) at the end? Since it is after while(temp != NULL) it means temp must equal null. Are you trying to free the whole list or what?
Your head pointer points to the last object, thats why you get the numbers 'backwards'.
input: 1, 2, 3
head[data: 3] (last thing temp pointed to) -> next[data: 2] -> next[data: 1] -> NULL
it is working correctly..you want to put new node in front of the list, right? after 1, you are adding so. so now the list will be: 2->1, and in the same way, 3->2->1

Resources