Maintaining chain of pointers to address - c

This is something of a followup to a question I asked earlier. I'm still learning my way around pointers, and I'm finding it difficult to maintain a reference to the physical address of a struct while iterating through a data structure. For example, I have a simple, barebones linked list that I'd like to delete from via a searching pointer:
struct Node{
int value;
struct Node* next;
};
struct Node* createNode(int value){
struct Node* newNode = malloc(sizeof *newNode);
newNode->value = value;
newNode->next = NULL;
return newNode;
}
void nodeDelete(Node **killptr){
free(*killptr);
*killptr = NULL;
}
int main(){
struct Node* head = createNode(16);
head->next = createNode(25);
head->next->next = createNode(51);
head->next->next->next = createNode(5);
// Working code to delete a specific node with direct reference address
struct Node** killptr = &head->next;
nodeDelete(killptr);
return 0;
}
The above shows deleting by passing nodeDelete a pointer to the address of the head pointer. What I want to do is be able to move my pointer ->next until it finds something that satisfies a delete condition, and call nodeDelete on that. I've tried the following:
struct Node* searchAndDestroy = head;
while(searchAndDestroy->value != NULL){ // Search until the end of the structure
if (searchAndDestroy->value == 25){ // If the value == 25
nodeDelete(&searchAndDestroy); // Delete the node (FAILS: Nullifies the
// address of search variable, not the
break; // original node)
}else{
searchAndDestroy = searchAndDestroy->next;
}
}
I've also tried something along the lines of:
if (searchAndDestroy->value == 25){
struct Node** killptr = (Node**)searchAndDestroy);
nodeDelete(killptr); // Still fails
}
I need to be able to move my pointer to the ->next point, but also maintain a reference to the address of the node I want to delete (instead of a reference to the address of the search node itself).
EDIT: Some clarification: I realize that deleting from a linked list in this fashion is naive, leaks memory, and drops half the list improperly. The point is not to actually delete from a linked list. Ultimately the idea is to use it to delete the leaves of a binary search tree recursively. I just figured a linked list would be shorter to portray in the question as an example.

struct Node **searchAndDestroy;
for (searchAndDestroy = &head;*searchAndDestroy; searchAndDestroy = &(*searchAndDestroy)->next ){
if ((*searchAndDestroy)->value == 25){
nodeDelete(searchAndDestroy); // Function should be changed to assign the ->next pointer to the **pointer
break;
}
}
And change nodeDelete like this:
void nodeDelete(Node **killptr){
Node *sav;
if (!*killptr) return;
sav = (*killptr)->next;
free(*killptr);
*killptr = sav;
}

Unless I'm missing something, your nodeDelete function is working as designed, but you want to keep a way of accessing the next node in the chain. The easiest way of doing this is just to add a temporary variable:
struct Node *searchAndDestroy = head, *temp = NULL;
while(searchAndDestroy != NULL){ // Need to check if the node itself is null before
// dereferencing it to find 'value'
temp = searchAndDestroy->next;
if (searchAndDestroy->value == 25){
nodeDelete(&searchAndDestroy);
break;
}else{
searchAndDestroy = temp;
}
}

if you give the Address of the previous Node that is where the link to deleting node present then it is very simple
code snippet for that:-
void delete_direct (struct Node *prevNode)
{/*delete node but restrict this function to modify head .So except first node use this function*/
struct Node *temp;/*used for free the deleted memory*/
temp=prevNode->link;
prevNode->link=temp->link;
free(temp);
}
struct Node * find_prev(struct Node *trv_ptr,int ele)
{
/*if deleting element found at first node spl operation must be done*/
if(trv_ptr->data==ele)
return trv_ptr;
while((trv_ptr->link)&&(trv_ptr->link->data!=ele))
{
trv_ptr=trv_ptr->link;
}
if(trv_ptr->link==NULL)
{
return NULL;
}
else
return trv_ptr;
}
main()
{
/*finding Node by providing data*/
struct Node *d_link;
struct Node *temp;
d_link=find_prev(head,51);
if(d_link==NULL)
{//data ele not present in your list
printf("\nNOT FOUND\n");
}
else if(d_link==head)
{//found at first node so head is going to change
temp=head;
head=head->link;
free(temp)
}
else
{//other wise found in some where else so pass to function
delete_direct (d_link);
}
}

Related

Merge Sort On Linked List in C

Merge sort is often preferred for sorting a linked list. The slow random-access performance of a linked list makes some other algorithms (such as quicksort) perform poorly, and others (such as heapsort) completely impossible.
I have been struggling to do Merge Sort on a linked list. It keeps throwing back an error. I'm providing the code I've tried to execute. Please do help me out.
It keeps giving runtime error.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *SortedMerge(struct node *a, struct node *b);
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref);
struct node *Create(struct node *head, int num) {
struct node *newnode, *temp;
newnode = (struct node *)malloc(sizeof(struct node));
newnode->data = num;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
temp = newnode;
} else {
temp->next = newnode;
temp = temp->next;
}
temp->next = NULL;
return head;
}
struct node *display(struct node *head) {
struct node *temp;
temp = head;
while (temp != NULL) {
printf("%d->", temp->data);
temp = temp->next;
}
printf("NULL");
return head;
}
struct node *MergeSort(struct node *head) {
struct node *headref, *a, *b;
headref = head;
if ((head == NULL) || (head->next) == NULL) {
return;
}
FrontBackSplit(headref, a, b);
MergeSort(a);
MergeSort(b);
head = SortedMerge(a, b);
return head;
}
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref) {
struct node *fast, *slow;
slow = source;
fast = source->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
frontref = source;
backref = slow->next;
slow->next = NULL;
}
struct node *SortedMerge(struct node *a, struct node *b) {
struct node *result;
result = NULL;
if (a == NULL) {
return (b);
}
else if (b == NULL) {
return (a);
}
if (a->data <= b->data) {
result = a;
result->next = SortedMerge(a->next, b);
} else {
result = b;
result->next = SortedMerge(a, b->next);
}
return result;
}
int main() {
struct node *head = NULL;
int i, n, num;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &num);
head = Create(head, num);
}
head = MergeSort(head);
display(head);
}
There are a couple of problems with the code, and which one triggers the error you are seeing I cannot say, but I will point out a few of them below. Take Create():
struct node *Create(struct node *head, int num)
{
struct node *newnode, *temp;
newnode=(struct node *)malloc(sizeof(struct node));
newnode->data=num;
newnode->next=NULL;
if(head==NULL) {
head=newnode;
temp=newnode;
} else {
temp->next=newnode;
temp=temp->next;
}
temp->next=NULL;
return head;
}
I cannot work out exactly what it is supposed to do, to be honest. Maybe add a new node to a list, represented by a head link? It doesn't do that. You create a new node
newnode=(struct node *)malloc(sizeof(struct node));
which I would suggest you write as
newnode = malloc(sizeof *newnode);
You don't need to cast void *, so you don't need to cast the result of malloc(), and using sizeof *newnode rather than sizeof(struct node) is safer. But the code works correctly in the form you have, so there is not a problem there. However, what happens with that node depends on head. If head is NULL, you point it at the new node, and through temp you (re)assign the new node's next to NULL. So now you will return an updated head that consists of the new node as a single element list. That matches my guess at what the function should do.
However, if head is not NULL, you put the new node in temp->next, which is a problem, since temp isn't initialised. You write to temp in the if(head==NULL) branch, but you dereference it in the else branch, where it can point anywhere. I am surprised if you don't get a segmentation fault from time to time here. It isn't necessary to assign the new node to temp->next, though, because immediately afterwards you change temp to point to temp->next, which is where you just put newnode, so temp = newnode would do the trick, without the segfault. But not all is well if we do that. We now would have the new node in temp (with the next pointer, again, reassigned to NULL) and then we return head. We didn't connect head with newnode anywhere, if we took the else branch. So calling Create() with a non-NULL head creates a new node, throws it away (and leaking memory), and that is all that does.
So while my guess is that Create() should add a new to a list, represented by head, or something to that effect, what it actually does is create a single-element list if the first argument is NULL, and leak sizeof(struct node) memory while doing nothing if head != NULL.
That being said, the code might work by pure luck of course. When I tried it with clang with zero optimisation, I somehow managed to build a list correctly. This is luck, though. It won't work in general. I suspect that what happens is that the repeated calls to Create() in the loop in main() happens to leave the last node you created (and wrote to temp) at the same stack location as the uninitialised temp in the next call. So by pure luck, putting the new node in temp's next appends the new node to the last node you created. It was really interesting working that one out :) But don't rely on this, of course. It is a combination of several lucky circumstances. Add optimisation flags, and the compiler will change the stack layout, and the code will break. Call other functions between successive calls to Create() and the stack will change, and then you don't have the last link on the stack any longer. And the code will break. It is a very unstable situation if this works at all.
If you just want to add a new node to a list, make a prepend function. Something like
struct node *prepend(int val, struct node *list)
{
struct node *n = malloc(sizeof *n);
if (n) {
n->data = val;
n->next = list;
}
return n;
}
(I haven't tested it, so there might by syntax errors, but it will be something like that...you need to figure out what to do if malloc() fails, but you could just abort() if you don't want to deal with it).
There is nothing wrong with display(), except that I don't understand why it is in lower-case when the other functions are in camel-case. You don't need temp, you can use head in the while-loop, but that is a style choice. The function works as intended.
With MergeSort(), however, we have another problem. I am surprised that your compiler didn't scream warnings at you here. It should really give you an error, with the right flags, but at the very least an error. When you test if the list is empty or a singleton, you return, but not with a node. The function should return a struct node *, so just using return will not give you anything useful.
if((head==NULL) || (head->next)==NULL){
return;
}
If the base case of the recursion returns garbage, obviously the whole recursion tumbles. Otherwise, assuming that the FrontBackSplit() and SortedMerge() work, the function looks okay. You don't need the extra headref variable, it is just a synonym for head, but there is nothing wrong with having it. The compiler will get rid of it for you. There isn't any need to assign the merged lists to head and then return head either. You can just return SortedMerge(a,b). But again, your compiler will handle that for you, once you turn on optimisation. Except for the base case, I believe the function should work.
In FrontBackSplit(), I get the impression that you want to get the frontref and backref values back to the caller. Otherwise, the function doesn't do anything. But when you are modifying the function parameters, you are not changing the variables in the caller's scope. You need to pass the two pointers by reference, which means that you need to use pointers to pointers. Change it to something like this:
void FrontBackSplit(struct node *source,
struct node **frontref,
struct node **backref)
{
struct node *fast, *slow;
slow=source;
fast=source->next;
while(fast!=NULL) {
fast=fast->next;
if(fast!=NULL) {
slow=slow->next;
fast=fast->next;
}
}
*frontref=source;
*backref=slow->next;
slow->next=NULL;
}
When you call the function, use the addresses of the parameters for the second and third argument, so use FrontBackSplit(headref,&a,&b); instead of FrontBackSplit(headref,a,b);.
As far as I can see, SortedMerge() should work (with a modified FrontBackSplit()). It is recursive, but not tail-recursive, so you might have problems with overflowing the stack for long lists. It isn't hard to make iterative, though.
You should make main() either int main(void) or int main(int, char**). You should return 0 for success.
My guess is that one of three things are breaking your code. When you Create() your lists, you do not get the lists you want. In just the right circumstances, with just the right compiler and function call configurations, however, you might get lucky (and maybe that is what you have seen). In that case, it might be the return in MergeSort(). Return head instead, there, that is probably what you want. If you have an empty list or a list of length one, you should return that list. So change return; to return head;. And if it isn't that either, it is probably because you recurse on random data in MergeSort(), because a and b aren't initialised in the recursion. They are uninitialised when you call FrontBackSplit() and the call doesn't change them, because they are passed by value and not reference. The change I listed above will fix that.
There might be more that I have overlooked, but at least those three issues are enough to break the code, each of them on their own, so it is a good place to start with debugging.

C: Function do Delete a Node on a Generic Linked List

I'm having trouble writing a function that will delete a node on a generic linked list.
I have my linked list declared as follow (this is the way my professor wants us to do):
typedef enum _STATUS {ERROR,OK} STATUS;
typedef enum _BOOLEAN {FALSE, TRUE} BOOLEAN;
#define MAX_NOME 20
typedef struct _FUNC
{
char name[MAX_NOME];
char dept[MAX_NOME];
BOOLEAN permanent;
} FUNC;
typedef struct _LIST_NODE
{
void * data;
struct _LIST_NODE * next;
} LIST_NODE;
typedef LIST_NODE * LIST;
#define DATA(node) ((node)->data)
#define NEXT(node) ((node)->next)
I've come with this function to delete all nodes with permanent == FALSE, but it is really not working.
void DeleteFuncNotPermanent(LIST *list)
{
LIST *node = list;
while ((*list)->next != NULL)
{
if(((FUNC*)DATA(*list))->permament == FALSE)
{
node = list;
list = &(NEXT(*node));
free(DATA(*node));
free(*node);
}
else
{
list = NEXT(*list);
}
}
}
Any feedback would be greatly appreciated. Thank you.
You iterate through the list with a pointer to node pointer, which is a good idea. (Typecasting away the pointer nature of LIST is not a good idea, however.) There are several errors in yur code.
To get a pointer to the last element of a list, you do:
Node **p = &head;
while (*p) {
p = &(*p)->next;
}
Your respective code, i.e. your function without the deletion stuff, looks like this:
while ((*list)->next != NULL) {
list = NEXT(*list);
}
You should iterate while (*list). The idea to check next probably stems from similar code that uses a node pointer to iterate. When you use a pointer to node pointer, dereferencing that pointer has the same effect as accessing next, because that pointer points to the head node at first and to the previous node's next member on subsequent iterations.
That's why you must assign the address of (*list)->next to list when you want to advance the pointer. (The comiler warns you that the pointer types don't match.)
So the "raw" loop should be:
while (*list != NULL) {
list = &NEXT(*list);
}
Now let's look at deletion. When you have determined that the node should be deleted, you do:
LIST *node = list;
list = &(NEXT(*node));
free(DATA(*node));
free(*node);
Here, you do not want to advance the iterator pointer. Instead, you want to update what it points at: You want to skip the current node *list by deflecting the pointer that points to the node to the next node or to NULL, when that was the last node:
*list = NEXT(*node);
When you do that, list and node will still be the same address, only the contents have changed. (Because node == list, *node now points at the node after the node you want to delete and you accidentally free that node and its data. Make the temporary pointer a simple node pointer:
LIST node = *list;
*list = NEXT(node);
free(DATA(node));
free(node);
Putting it all together:
void DeleteFuncNotPermanent(LIST *list, int c)
{
while (*list)
{
if (((FUNC*) DATA(*list))->permament == FALSE)
{
LIST node = *list;
*list = (NEXT(*list));
free(DATA(node));
free(node);
}
else
{
list = &NEXT(*list);
}
}
}
I have tried to rewrite your delete function. Let me know if it works. The changes are basically related to pointer dereferencing.
void DeleteFuncNotPermanent(LIST *list)
{
LIST *node = list;
while (list!= NULL) // change
{
if(((FUNC*)(DATA(list)))->permament == FALSE) // change
{
node = list;
list = NEXT(node); //change
free((FUNC*)(DATA(node))); // change
free(node); // change
}
else
{
list = NEXT(list); //change
}
}
}

Pointer is not being passed during a linked list swap

This will most likely seem like I am missing something obvious but when I try to pass a Linked List pointer to my Selection sort I get a NULL pointer problem. In my C code I have this as my linked list:
typedef struct iorb
{
int base_pri;
struct iorb *link;
char filler[100];
} IORB;
Then I pass my new linked list into this function after creating it:
void swapNodes(POINTER *head, POINTER CurrentHead, POINTER CurrentMinimum, POINTER TempSwap);
POINTER SortList(POINTER *head, char *SortMethod[])
{
POINTER TempHead = *head;
//Only one node, no need to sort.
if (TempHead->link == NULL)
{
return head;
}
//Store node with the new minimum value.
POINTER TempMin = *head;
//Store curent node for swapping
POINTER TempSwap = *head;
//Transverse the list.
POINTER TempCurrent;
for (TempCurrent = *head; TempCurrent->link != NULL; TempCurrent = TempCurrent->link)
{
//Check if this node has a lower priority than the current minimum and if so, swap them.
if (TempCurrent->link->base_pri < TempMin->base_pri)
{
TempMin = TempCurrent->link;
TempSwap = TempCurrent;
}
}
//Swap nodes if the head is not the same as the minimum.
if (TempMin != TempHead)
{
swapNodes(&TempHead, TempHead, TempMin, TempSwap);
}
//Recursively sort the rest of the list.
//FOR SOME REASON THE NODE POINTER IS NOT BEING PASSED HERE (EMPTY)
TempHead->link = SortList(TempHead->link, *SortMethod);
return head;
}
void swapNodes(POINTER *head, POINTER CurrentHead, POINTER CurrentMinimum, POINTER TempSwap)
{
//Set new head as the minimum.
*head = CurrentMinimum;
//Link the current temp swap to the head.
TempSwap->link = CurrentHead;
//Swap pointers.
POINTER temp = CurrentMinimum->link;
CurrentMinimum->link = CurrentHead->link;
CurrentHead->link = temp;
}
I am not sure why it is isn't being passed back into the same function, when I debug the linked list seems okay. I suspect that I am missing something in the swap node function, but I don't quite understand what this is. Can someone please offer some insight as to how this code should go for swapping the nodes around?
If you need additional information please let me know.
SortList(TempHead->link, *SortMethod); needs to be listed as SortList(&TempHead, *SortMethod);
To correctly pass the pointer.

Pop() function that crashes

I am trying to implement a stack with linked lists. I am having problems with the pop() function. It compiles OK, but when I try to run the code it crashes on tmp=tmp->head; and I have no idea why. I tried google but didn't find the answer. Here is the full code:
struct node{ //kreiram stog
struct node* head;
struct node* next;
int broj;
}node;
void push_onto(int broj){ // dodajem na glavu
struct node* novi;
novi=(struct node*)malloc(sizeof(struct node));
//novi=novi->head;
if (novi== NULL)
printf("Smth is wrong,Jose!\n");
else
novi->broj=broj;
novi->next=novi->head;
novi->head=novi;
}
int pop()// skidam sa stoga
{
struct node* temp;
temp=temp->head;
int br;
if (temp->next==NULL)
return -1;
else
br=temp->head;
temp=temp->next;
free(temp);
return br;
}
void top(){ //koji je element na stogu
struct node* tmp;
printf("Trenutni element na stogu je %d",tmp->broj);
}
void is_empty(){
struct node* tmp;
tmp=tmp->head;
if (tmp->head ==NULL)
printf("List is empty!\n");
}
void print_elem(){
struct node* tmp;
tmp=tmp->head;
if (tmp->head==NULL)
printf("Smth gone wrong!\n");
while (tmp!=NULL)
{
printf("Number is: %d",tmp->broj);
tmp=tmp->next;
}
printf("\n");
}
int main(void){
push_onto(15);
push_onto(10);
push_onto(20);
push_onto(12);
//print_elem();
printf("The element removed is : %d",pop());
//print_elem();
return 0;
}
This is not my homework, although it looks as such. This is just my attempt at trying to figure out some basic algorithms.
Thanks in advance! :)
struct node* temp;
temp=temp->head;
You never allocated anything for temp. It's just an uninitialized pointer.
It's not clear what you are trying to pop. Your pop() function takes no parameters and it accesses no globals. Likewise, I see the same problem with most of your functions there. They are supposed to operate on some sort of stack object, but none of them actually take such an object as a parameter.
I think you're close to "getting it". I remember it was a bit hard for me to understand structs and pointers at the beginning. But once you "get it" you'll be fine.
It seems you're trying to construct a stack using a simply-linked list. I'll try to offer some suggestions.
The very first thing that I would modify is your node struct. It is true, you need to keep
track of the head node, but usually you don't need to do it on every node. So we will remove it from your node definition.
struct node{ //kreiram stog
struct node* next;
int broj;
};
Now, you need to keep track of the head node of your list. This can be done with a global variable, that I'm going to call head:
struct node* head = NULL;
I'm initializing it to null because it is empty. A null head pointer will always mean
your stack is empty. All the code that tries to manipulate the list WILL need to start
with this head node. It is your anchor point.
Then to the push_onto() function
void push_onto(int broj){ // dodajem na glavu
// this bit is fine
struct node* novi;
novi=(struct node*)malloc(sizeof(struct node));
if (novi== NULL)
printf("Smth is wrong,Jose!\n");
else { //I'm adding the bracket, you require it to enclose more than one statement
//in the else section
novi->broj = broj; // store the number to be pushed on the stack
novi->next = head; // link the list, remember head will
// be NULL if the stack was empty
head = novi; // make the new node the current head node
}
}
Let's modify the pop() function
int pop()// skidam sa stoga
{
struct node* temp;
int result;
// first we will check if the head node is NULL (stack is empty)
if( head == NULL ) {
printf("Stack is empty\n");
return -1;
} else {
// hold a temporary value to current head pointer, so we can modify the head node
// and still refer to it
temp = head;
// Head node should now point to the next node on the list (will become NULL when
// popping the last value. This is what actually "pops" the value from our list
head = head->next;
// place in temporary variable the result we are popping. This is so because
// it's not a good idea to reference the node after we free the memory it is using
result = temp->broj;
// release the memory occupied by the node we're popping
free(temp);
return result;
}
}
Finally I'm going to show you how to fix some of the functions that are using your stack
void top(){ //koji je element na stogu
if( head == NULL ) {
printf("Stack is empty\n");
} else {
printf("Trenutni element na stogu je %d",head->broj);
}
}
void print_elem(){
struct node* tmp;
// As you can see, we're initializing tmp to head, since head will always point
// to the top element of your stack.
tmp = head;
if (tmp==NULL) {
printf("Stack is empty!\n");
return;
}
while (tmp!=NULL)
{
printf("Number is: %d",tmp->broj);
tmp=tmp->next;
}
printf("\n");
}
Hope things are clearer now. The head node is kept apart as a global variable and as I said before, it is the anchor point to begin manipulating the list. Feel free to ask me if you're still confused.
=)

Deleting a node from array of linked lists?

I'm writing a hashtable as an array of linked lists.Currently I'm trying to have a simple hash table where the key is the index of the array and value is a singly linked list for implementing chaining.
This is my code to delete a node:
Basic Struct:
struct Node
{
int value;
int page;
struct Node *next;
};
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
for(;*iter;iter=&(*iter)->next)
{
if(page==((*iter)->page))
{
if(frame==((*iter)->value))
{
if(delete)
{
(*prev)->next=(*iter)->next;
free(*iter);
}
return 1;
}
}
prev=iter;
}
return 0;
}
For insertion please take a look here, AddNode
When I'm deleting a node, the value for that changes to 0. When I search for the node it gives back that node is not preset aka 0 as output from the function.
Are there any mistakes in my code which I haven't thought about?Am I leaving any memory leaks or any other problems?
Edit
Added this piece of code to the delete function:
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
struct Node** curr=iter;
for(;*curr;curr=&(*curr)->next)
{
if(page==((*curr)->page))
{
if(frame==((*curr)->value))
{
if(delete)
{
if(curr==iter)
{
iter=(*curr)->next;
free(*curr);
}
else
{
(*prev)->next=(*curr)->next;
free(*curr);
}
}
return 1;
}
}
prev=curr;
}
return 0;
}
Problem I'm seeing is that when I delete the first time, the element is not freed, it's value is set to 0, but it still says in the linked list. In the second deletion the value of the last elements goes to some garbage and hence that element will never be deleted in my comparison checks. Can someone shed light on what I might be doing here?
If the hash table you're using is seven elements wide (i.e. 0..6 for indexes), and from your AddNode code, it appears it is, then the arithmetic you're using is suspect for the initial iterator find.
iter=&hashtable[page-1%7];
should likely be:
struct Node** iter = hashtable + (page % 7);
This will give you the address of the element in your hash table at the page location modulus 7, i.e. [0..6].
Also, your delete from your hash table head node doesn't account for clearing the table element itself. You may need to (a) set it to null, or (b) chain in the next ptr. Do that as well. You have the ability to since the hash table and the initial node pointer are both available.
EDIT: OP asked for sample. This is just a quick jot of how this can be done. I'm sure there are plenty of better ways, maybe even ones that compile. This assumes both the page AND frame must match EXACTLY for a node to be considered delete'able.
void searchAndDelete(int frame, int page, int del)
{
struct Node** head = hashtable + (page % hashtable_size);
struct Node* curr = *head;
struct Node* prev = NULL;
while (curr)
{
// if they match, setup for delete.
if ((curr->page == page) && (curr->value == frame) && del)
{
// so long as the header pointer is the active node prev
// will be NULL. move head along if this is the case
if (prev == NULL)
*head = curr->next;
// otherwise, the previous pointer needs it next set to
// reference the next of our vicitm node (curr)
else
prev->next = curr->next;
// victim is safe to delete now.
free(curr);
// set to the new head node if we just deleted the
// old one, otherwise the one following prev.
curr = (prev == NULL) ? *head : prev->next;
}
else
{ // no match. remember prev from here on out.
prev = curr;
curr = curr->next;
}
}
}
Eh, close enough =P
I see couple of issues:
mod operator % needs parenthesis. So change iter=&hashtable[page-1%7]; to iter=&hashtable[(page-1)%7];
Handle the case when you will delete 1st element in linked list. In such cases prev will be same as iter so (*prev)->next=(*iter)->next; will not make any different. You need to update the array to store next element aka (*iter)->next.

Resources