Delete a node in a singly linked list: C - c

I'm trying to write a program that deletes a node from a singly linked list.
void Delete(char * sym) {
// Pointer variable declarations.
struct SymbTab *search = Search(sym);
if (search == NULL) {
return;
}
struct SymbTab *p = search;
struct SymbTab *q = p->next;
p->symbol = p->next->symbol;
p->addr = p->next->addr;
p->next = p->next->next;
size--;
}
The "Search(sym)" redirects to my Search function, which returns a struct SymbTab* if it finds a match and NULL if no match is found. I keep getting a seg fault, but I'm unsure as to where I'm incorrectly assigning/declaring/etc things to memory. (edit: fixed the code indentation)

In a single linked list, unlike in a double linked list (where you have the reference to the previous item), you need to keep the previous item at hand, which could be done like this:
for (
item_type *item = lst->head, //start with first item in the list
*prev = NULL; //the previous item, initially NULL
item; //as long as item is not NULL
item = item->next //increase to next item in the list
){
if (equals(item, item_to_delete)) { //if the item is the item you're looking for
if (prev) { //item is not first item
prev->next = item->next; //remove the item
} else { //first item in the list
lst->head = item->next; //set new head
}
delete(item); //delete the removed item
break; //or return
}
prev = item; //keep the previous item at hand
}

Related

C how to iterate and add a new node after a desired node in single Linked List

typedef struct ITEM {
int value;
struct ITEM *next;
}ITEM;
int add_after(ITEM *list, ITEM *c_item, int value)
{
ITEM *elem;
//if head is NULL, it is an empty list
if(c_item == NULL || list == NULL)
{
return -1;
}
//create a new node
elem = malloc(sizeof(ITEM));
if(elem == NULL)
{
return -1;
}
elem->value = value;
// iteration
while(list != NULL)
{
if(list == c_item)
{
elem->next = list->next;
c_item->next = elem;
return 1;
}
list = list->value;
}
return 0;
}
What it should do:
c_item should be equal to one of the exiting nodes in the list. After finding an equal, it should make a new node elem and put that node infront of c_item.
What my code does:
list is HEAD value and compared with the c_item value and if its not the same then list goes to the next value in the list. After finding the equal, then it adds elem node to the list infront.
Problem:
This only works with 1 existing node in the list. If there is 2 nodes then it gets stuck at list = list->value;.
// Linked List 10->20->30->NULL
//Input:
c_item = 20
elem = 100
//Output:
10->20->100->30->NULL
You seem to have the basics of most of what you want to do in place. Let's try to to reorganize your pieces, and perhaps you can get close to your desired solution.
I would first use comments to describe what I want to accomplish in the function.
int add_after (ITEM *list, ITEM *c_item, int value) {
// Check c_item and list are not NULL
// Check if c_item is in list
// Create new elem with value
// Add new elem after c_item
}
Then, I would write the code that accomplishes each of these things.
Check c_item and list are not NULL
if (! (c_item && list)) return -1;
Check if c_item is in list
if (! list_has_item(list, c_item)) return -1;
Create new elem with value
ITEM *elem = create_item(value);
if (elem == NULL) return -1;
Add new elem after c_item
ITEM *old_after = c_item->next;
c_item->next = elem;
elem->next = old_after;
This last bit actually the specific question you ask about. The implementation remembers what used to be after the the c_item, makes the new element to be after it instead, then puts what used to be after c_item after the new element.
It is possible to make the same thing happen without the temporary. It is debatable what is more clear, but if you are curious, feel free to try to rewrite the three lines of above into two lines instead.
I think you already understand how to check if an item is in the list and how to create a new item, so I will leave those up to you to implement.

Remove last node of a linked list, and add this to another linked list

I'm trying to figure out how to manipulate linked lists. I want to remove the end node of a given linked list and add this to the end of another given linked list.
For some reason I can not get my pointers right, well- at least that is where I think the problem lays.
(This method sits in a while loop, so one list keeps getting smaller while the other one grows.)
void movenode(struct Node **cards,struct Node **column)
{
struct Node *head = NULL;
struct Node *tmp,*head1 = *cards;
struct Node *tmp2,*head2 = *column;
if (*cards == NULL || (*cards)->next == NULL){
return;
}
while (tmp->next != NULL) {
head->next = tmp;
tmp = tmp->next;
}
while (tmp2->next != NULL) {
tmp2 = tmp2->next;
}
head->next = NULL;
tmp2->data = tmp;
tmp2->next = NULL;
*cards = head1;
*column = head2;
}
Hope someone is able to help me better understand this.
For some reason I can not get my pointers right, well.. atleast that is where I think the problem lays.
You're right, but it's a little more than that. For example, after struct Node *head = NULL; nothing modifies the value in head, so every time you do head->next you're accessing memory at "NULL + a small offset" (and will probably crash).
To remove the last entry from a singly linked list, you have to find the entry before the last entry (so that you can modify its next); and to add an entry to a linked list you have to find the last entry (so that you can modify its next). With this in mind we can break it into 5 parts:
Do sanity checks
Find the entry before the last entry in the *cards list
Remove the last entry in the *cards list
Find the last entry in the *column list
Add the (removed) entry to the end of the *columns list
You can implement each of these 5 pieces one at a time (and test them). This is an important part of programming - breaking more complex stuff into simpler easier things.
The resulting code might look something like (untested):
void movenode(struct Node **cards,struct Node **column) {
struct Node *temp = *cards;
struct Node *removed;
// Do sanity checks
if (temp == NULL) {
return;
}
// Find the entry before the last entry in the `*cards` list
if(temp->next != NULL) {
while(temp->next->next != NULL) {
temp = temp->next;
}
}
// Remove the last entry in the `*cards` list
if(temp == NULL) {
// The last entry was the first entry
removed = temp;
*cards = NULL;
} else {
removed = temp->next;
temp->next = NULL;
}
// Find the last entry in the `*column` list
temp = *column;
if(temp != NULL) {
while(temp->next != NULL) {
temp = temp->next;
}
}
// Add the (removed) entry to the end of the `*columns` list
if(temp == NULL) {
// There was no last entry (list was empty)
*column = removed;
} else {
temp->next = removed;
}
}
I'm not entirely sure about the mechanics of your solution so I'll offer a separate implementation and solution.
typedef struct Node {
void *data;
struct Node *next;
}
void poppush(Node *popHead, Node *pushHead) {
Node *pushLastNode = pushHead;
while (pushLastNode->next != NULL) {
pushLastNode = pushLastNode->next;
}
Node *popLastNode = popHead;
while (popLastNode->next != NULL) {
popLastNode = popLastNode->next;
}
Node *popSecondLastNode = popHead;
while (popSecondLastNode->next != popLastNode) {
popSecondLastNode = popSecondLastNode->next;
}
popSecondLastNode->next = NULL;
pushLastNode->next = popLastNode;
}
However, for operations such as these, I would recommend using a doubly-linked list and/or create some functions dedicated to managing the lists.

singly linked list head and tail method?

I'm relatively new to c programming language, and was playing around to get familiar with it, but I'm not sure how to actually implement a linked list with the following structs and data I'm trying to do(below). Basically the goal is to add an item from a singly linked list with a head and tail.
Update: I tried to do write some code in my add function, haven't sorted it but is that how it would look like?
CODE SOURCE
typedef struct {
char car_model[32],car_name[32];
} CarObjects;
typedef struct myNode{
struct myNode* next;
CarObjects* data;
} MyList;
//initialize list
void declareList(MyList* someList){
someList->next = NULL;
}
void insertElementByTitle(MyList* someList, CarObjects* someCar){
//first case adding to an empty list.
if(someList == NULL){
someList = malloc(sizeof(MyList));
someList->data = someCar;
someList->next = NULL;
}
//END OF first case adding to an empty list.
//make thee list's head and tail node, point to the first element since its an empty list
someList->head = someList;
someList->tail = someList->head;
while(someList->next != NULL)
someList = someList->next;
someList->next = malloc(sizeof(MyList));
someList = someList->next;
someList->data = newBook;
someList->next = NULL;
}
int main(){
MyList* listHead= NULL;
MyList* listTail= NULL;
//Somehow add an element to the list
return 0;
}
At first properly define your structure.
typedef struct car{
char car_model[32],car_name[32];
};
typedef struct myList{
myList * next;
car * carObject;
};
Now, you are trying to insert as the Insertion Sort technique.
void insertElementByTitle(MyList* someList, CarObjects* someCar){
\\I assume someList is pointing the head of the linked list
\\One more assumption that, the Linked List is already sorted and need to inset
\\someCar in the correct position.
MyList *secondPointer = someList->next;
while(secondPointer != null)
{
if(ifCarIsInBetweenSomeListAndSecondPointer(someList,secondPointer,someCar))
{
someList->next = newNode(someCar);
someList->next->next=secondPointer;
break;
}
someList = secondPointer; secondPointer = secondPointer->next;
}
if(secondPointer == null)
{
someList->next = newNode(someCar);
}
}
Now, you need two function
myNode* newNode(car * someCar);
bool ifCarIsInBetweenSomeListAndSecondPointer(myNode *someList,myNode *secondPointer,car *someCar);
myNode* newNode(car * someCar){
myNode * t =(struct myNode*)malloc(sizeof(struct myNode));
t->carObject = someCar;
t->next= null;
return t;
}
bool ifCarIsInBetweenSomeListAndSecondPointer(myNode *someList,myNode *secondPointer,car *someCar){
if( (strcmp(someList->carObject->car_name,someCar->carObject)<0) &&(strcmp(someCar->carObject,secondPointer->carObject->car_name)<0))
return true;
return false;
}
Refer online reference such as geeksforgeeks-linked list, to get better understanding.

Segmentation fault during insertion of node into linked list

I am attempting to alphabetize two separate lists in my add function: one that sorts the nodes by first names, and another that sorts by last names. I also have some logic that checks if a name is already in the list and if it is an error is printed and the list is returned unchanged. Like the title says, I am getting a segmentation fault here and am not sure why. It may be a pretty basic problem but I am new to C and especially new to linked lists.
Here is how the nodes are defined:
typedef struct node {
char *first;
char *last;
long number;
struct node *nextFirst;
struct node *nextLast;
} Node;
typedef struct mlist {
Node *headFirstName;
Node *headLastName;
} MultiLinkedList;
And here is my add function:
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
//make placeholder nodes
Node *a = list->headFirstName;
Node *b = list->headLastName;
// add this new node at the head of the "byFirst" list
if (strcmp(newNode->first, a->first) < 0) {
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
}
for (Node *i = list->headFirstName; i; i = i->nextFirst) {
// add after less alphabetical nodes
if (strcmp(newNode->first, i->first) > 0) {
newNode->nextFirst = i->nextFirst;
i->nextFirst = newNode;
}
// return error for duplicate name
if (strcmp(newNode->first, i->first) == 0 && strcmp(newNode->last, i->last) == 0) {
printf("That person is already in the list! Please try with a different name.\n");
}
}
// add this new node at the head of the "byLast" list
if (strcmp(newNode->last, b->last) < 0) {
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
}
for (Node *j = list->headLastName; j; j = j->nextLast) {
// add after less alphabetical nodes
if (strcmp(newNode->last, j->last) > 0) {
newNode->nextLast = j->nextLast;
j->nextLast = newNode;
}
}
// return the multi-list object with updated or original head pointers
return list;
}
I figured out what my problem was. I had to add return list; to the end of each if statement otherwise the function attempts to perform every true statement; which causes the seg fault. In hindsight I'm surprised I didn't figure this out sooner.

Delete function in circular linked list changing next and previous to null when only one node left

In my delete function for a circular doubly linked list when I enter the function with two nodes and delete one node it is changing my next node and previous node to null. This only happens when I enter the function with two nodes in the linked list. I am using breakpoints in eclipse and everything seems to be working until I end the function and return the temp. After that the next and previous for ptrLocal get set to NULL. Not really sure why.
Here is the function call
struct TCB_t del = delete_from_list(&RunQ);
Here is the function
struct TCB_t delete_from_list(struct TCB_t **ptrLocal)
{
struct TCB_t temp;
if(*ptrLocal)
{
temp = **ptrLocal;
temp.next = NULL;
temp.previous =NULL;
if(*ptrLocal == (*ptrLocal)->next->next)
{
*ptrLocal = (*ptrLocal)->next;
(*ptrLocal)->next = *ptrLocal;
(*ptrLocal)->previous = *ptrLocal;
}
else if(*ptrLocal != (*ptrLocal)->next)
{
(*ptrLocal)->previous->next = (*ptrLocal)->next;
(*ptrLocal)->next->previous = (*ptrLocal)->previous;
*ptrLocal = (*ptrLocal)->next;
}
else
{
(*ptrLocal)->previous = NULL;
(*ptrLocal)->next = NULL;
*ptrLocal =NULL;
}
count--;
}
return temp;
}
After return temp ptrLocal->next and preLocal->previous are both set to null.
Your error is the last else. it applied when there is single node in the list.
In Circular linked list, next and previuos never shouldn't be NULL
Therefor if there is only 1 item, next and previous should point to itself.
Now your you should check like this:
if ((*ptrLocal)->next = (*ptrLocal)){ //delete the last item in the list, should NULL the pointer
free(*ptrLocal);
*ptrLocal=NULL;
}
else {
(*ptrLocal)->previous->next = temp->next;
(*ptrLocal)->next->previous = temp->previous;
free(*ptrLocal);
}
I don't see the reason to check for two items:
For example A<->B<->A
And you delete B:
if you go to the else: you get A<->A which is still a circular list.

Resources