I'm reading in words from a dictionary and then adding them to linked lists in a hash table. This works fine when I try inserting the nodes for each word within the while loop.
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
return false;
}
// Set all next pointers to NULL in hash table
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
char word[LENGTH + 1];
while(fscanf(dict, "%s", word) != EOF)
{
// Get key from hash function
unsigned int key = hash(word);
node *pNode = getNode(word);
if (table[key] != NULL)
{
pNode->next = table[key];
}
table[key] = pNode;
words++;
}
fclose(dict);
return true;
}
I've tried refactoring this to a function insertNode with the exact same code but it doesn't work and the nodes seem to get lost and cause a memory leak. I assume it has something to do with how the arguments are passed into the function but as head is a pointer I would've thought it would work fine.
void insertNode(node *head, const char *key)
{
// Create node
node *pNode = getNode(key);
// Insert node into linked list
if (head != NULL)
{
// Make new node point to first item in linked list (a.k.a head)
pNode->next = head;
}
// Now point head to new node
head = pNode;
}
so the while loop within load would just call the function (which is defined before)
char word[LENGTH + 1];
while(fscanf(dict, "%s", word) != EOF)
{
// Get key from hash function
unsigned int key = hash(word);
// Add value to Hash table with head of linked list
insertNode(table[key], word);
words++;
}
As the 'head' variable is a pointer, you can just pass the value of 'head' by this pointer not the pointer itself, and in this case you try to override the local pointer inside the function.
Well look at this example to assign/change value to the pointer:
#include <stdio.h>
class A {
public:
int x;
};
// pass pointer by copy
void initialize(A* obj) {
obj = new A(); // obj not null here
obj->x = 2;
printf("x: %d\n", obj->x);
}
int main() {
A *a = nullptr;
initialize(a);
// a is still null here (pointer passed by copy)
printf("x: %d\n", a->x); // seg fault here, read on null
return 0;
}
The following code as you can see is incorrect. To fix this example you have to change the function prototype, and pass the pointer by pointer so it should lool like this:
#include <stdio.h>
class A {
public:
int x;
};
// pass pointer by pointer
void initialize(A** obj) {
*obj = new A(); // obj not null here
(*obj)->x = 2;
printf("x: %d\n", (*obj)->x);
}
int main() {
A *a = nullptr;
initialize(&a); // get the pointer address
// a is valid object here
printf("x: %d\n", a->x); // no error, x == 2
return 0;
}
So in your case it should be:
insertNode(&table[key], word);
and
void insertNode(node **head, const char *key)
{
// Create node
node *pNode = getNode(key);
// Insert node into linked list
if (*head != NULL)
{
// Make new node point to first item in linked list (a.k.a head)
pNode->next = *head;
}
// Now point head to new node
*head = pNode;
}
Related
I'm adding words (character per node) on a trie data structure - that happens correctly based on a implementantion I found on the web -
http://www.techiedelight.com/trie-implementation-insert-search-delete/
Although I want to extend this and add a list containing some data based on the words, such term frequency etc.
Right now I'm facing an issue with the pointer of the list when adding the first element on a trie node - in the method append_posting_list - and getting a segmetation fault.
Here is the code so far.
main.h
#ifndef TRIE_H
#define TRIE_H
#define CHAR_SIZE 26
typedef struct posting_list {
int doc_id;
int tf;
int df;
struct posting_list *next;
} posting_list_node ;
struct Trie
{
posting_list_node *p_node; // this will be the head of the posting list for every word;
int isLeaf; // 1 when node is a leaf node
struct Trie* character[CHAR_SIZE];
};
struct Trie* getNewTrieNode();
void insert(struct Trie* *head, char* str, int doc_id);
int search(struct Trie* head, char* str);
#endif //TRIE_H
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(){
struct Trie* head = getNewTrieNode();
insert(&head, "hello", 1);
return 0;
}
// Function that returns a new Trie node
struct Trie* getNewTrieNode()
{
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
return node;
}
posting_list_node* get_mem(){
posting_list_node* p;
p = (posting_list_node *)malloc(sizeof(posting_list_node));
if (p == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return p;
}
void append_posting_list(int doc_id, posting_list_node **n){
posting_list_node *new, *q;
new = get_mem();
new->doc_id = doc_id;
new->tf = 1;
new->next = NULL;
// if new is the first element of the list
if(n == NULL) {
*n = new;
} else {
q = *n;
while( q->next!=NULL) {
q = q->next;
}
q->next = new;
}
}
// Iterative function to insert a string in Trie.
void insert(struct Trie* *head, char* str, int doc_id)
{
// start from root node
struct Trie* curr = *head;
while (*str)
{
// create a new node if path doesn't exists
if (curr->character[*str - 'a'] == NULL)
curr->character[*str - 'a'] = getNewTrieNode();
// go to next node
curr = curr->character[*str - 'a'];
// move to next character
str++;
}
// already found this word, increase frequency
if(curr->isLeaf) {
curr->p_node->tf += 1;
} else {
append_posting_list(doc_id, curr->p_node);
// mark current node as leaf
curr->isLeaf = 1;
}
}
// Iterative function to search a string in Trie. It returns 1
// if the string is found in the Trie, else it returns 0
int search(struct Trie* head, char* str)
{
// return 0 if Trie is empty
if (head == NULL)
return 0;
struct Trie* curr = head;
while (*str)
{
// go to next node
curr = curr->character[*str - 'a'];
// if string is invalid (reached end of path in Trie)
if (curr == NULL)
return 0;
// move to next character
str++;
}
// if current node is a leaf and we have reached the
// end of the string, return 1
return curr->isLeaf;
}
I'm really stuck here.
Any suggestions would be really appreciated.
I found a couple things that when fixed, got rid of your segmentation fault.
In getNewTrieNode() I think you need to set p_node to NULL
struct Trie* getNewTrieNode() {
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
node->p_node = NULL;
return node;
}
append_posting_list() takes post_list_node **, but in insert(), you are passing just post_list_node *
void append_posting_list(int doc_id, posting_list_node **n)
append_posting_list(doc_id, curr->p_node);
looks like it should be
append_posting_list(doc_id, &(curr->p_node));
In append_posting_list()
if (n == NULL) {
should be
if (*n == NULL) {
in order to see if a pointer to an empty list is being passed in.
You should really have some functions to print out your data structure while you are working on it, so you can test each piece as you develop it. Simply compiling and running code and not getting any errors is no gurantee the code is working correctly with complex data structures like this. Making sure that each piece works perfectly before going on to the next piece will save you hours in trying to track down segmentation faults and other errors like this.
I have this C function which is supposed to find an element in the linked list which has a specific "pos" value, delete it, and return the deleted value to the calling function. It does delete the item, but the change isn't saved in the calling function, the list just doesn't get updated with the new changes.
My list is structured like this:
struct list{
int value;
int pos;
struct list * next_ptr;
};
And my C function is this:
bool findDeleteElement(struct list **ptr, int position, int *value){
struct list** temp = ptr;
if(*ptr!=NULL){
while((*ptr)->pos!=position) ptr=&(*ptr)->next_ptr; //Gets to desired node
temp=ptr;
value=&(*ptr)->value; //saves the value
temp=&(*temp)->next_ptr; //Goes to next node
ptr=temp; //Makes ptr point to next node
return 1;
}
else return 0;
}
I just can't see what I'm missing.
I'm a beginner so I probably made a simple mistake.
Change to:
*value = (*ptr)->value; //saves the value
You only set value, the local copy of your external variable's address. This does not change your external variable in the calling function.
Some question:
What happens when position has the wrong value, such that no node is found?
What's the purpose of temp = ptr;, because temp is overwritten by temp = &(*temp)->next_ptr; without having been used.
Disclaimer: I've not further checked this function.
I kindly advise you to take on other code formatting rules that add more air and make things more readable. Here's an example:
bool findDeleteElement(struct list **ptr, int position, int *value)
{
struct list** temp = ptr;
if (*ptr != NULL)
{
// Gets to desired node
while((*ptr)->pos != position)
{
ptr = &(*ptr)->next_ptr;
}
temp = ptr;
*value = (*ptr)->value; // Saves the value
temp = &(*temp)->next_ptr; // Goes to next node
ptr = temp; // Makes ptr point to next node
return 1;
}
else
{
return 0;
}
}
You are confused about pointers and dereferencing and what & and * actually do. This is a normal state of affairs for a beginner.
To start with, ptr and value when used without * preceding them are function arguments and like automatic (local) variables they disappear when the function scope exits. So this statement:
value=&(*ptr)->value;
Merely changes the value of value i.e. what it points to and has no visible effect to the caller. What you need to change is the thing that value points to. i.e. the statement should look like this:
*value = (*ptr)->value;
The difference is that instead of setting value to the address of (*ptr)->value it sets what valuepoints to to (*ptr)->value.
You have a similar problem with ptr. But your problems are more subtle there because you are also trying to use it as a loop variable. It's better to separate the two uses. I'd write the function something like this:
bool findDeleteElement(struct list **head, int position, int *value)
{
struct list* temp = *head;
struct list* prev = NULL;
while(temp != NULL && temp->pos != position)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) // position not found
{
return false;
}
else
{
*value = temp->value;
// Now need to delete the node.
if (prev != NULL)
{
// If prev has been set, we are not at the head
prev->next = temp->next; // Unlink the node from the list
}
else // We found the node at the head of the list
{
*head = temp->next;
}
free(temp); // Assumes the node was malloced.
return true;
}
}
The above is not tested or even compiled. I leave that as an exercise for you.
int delete(struct llist **pp, int pos, int *result)
{
struct llist *tmp;
while ( (tmp = *pp)) {
if (tmp->pos != pos) { pp = &tmp->next; continue; }
*result = val;
*pp = tmp->next;
free(tmp);
return 1;
}
return 0;
}
I'm writing a simple C program to manage a linked list defined as follow:
typedef struct node {
int value;
struct node *next;
} *List;
I reviewed the code and it seems okay but when printing results something is not working well.
My main, with problems on comments:
int main(void) {
List n = list_create(1);
insert(n, 2);
insert(n, 3);
insert(n, 5);
insert(n, 4);
//something here does not work properly. It produces the following output:
//Value: 1
//Value: 2
//Value: 3
//Value: 4
//where is value 5?
print_list(n);
delete(n, 3);
print_list(n);
return 0;
}
I don't know where am I destroying list structure. These are my functions, to debug, if you are too kind.
List list_create(int value) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = NULL;
return new;
}
List new_node(int value, List next_node) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = next_node;
return new;
}
void print_list(List l) {
List *aux;
for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
printf("Valor: %d\n", (*aux)->value);
}
void insert(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value > value) {
List tmp = *p;
List new = new_node(value, tmp);
*p = new;
break;
}
*p = new_node(value, NULL);
}
void delete(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value == value) {
List del = (*p);
(*p) = ((*p)->next);
free(del);
break;
}
}
This code has (at least) two bugs:
The line
if ((*p)->value > value){
means that if you start the list with 1 as the first value and then try to insert 2,3,4..., the body of the 'if' statement never runs, so nothing ever gets inserted.
If you insert a value below the starting value, you have to modify the list pointer itself. However, as #EOF alluded, you are trying to modify a value passed to a function by taking its address. This won't work. &l does not give you the address of the List you passed, it gives you the address of the local copy on insert()'s stack. You are better off modifying the values of first element of the list 'in place'. If you really want to make the List parameter mutable, you'll need to pass it as a List *, and call the function with the address of the list (e.g. insert(&n,2); ) Your delete() function suffers from the same problem - try deleting the first element of the list.
Try this for your insert function:
void insert(List l, int value)
{
List p;
// Find end of list or highest item less than value
for(p = l; p->next != NULL && p->next->value < value; p = p->next);
if (p->value >= value) {
// Over-write p with new value, and insert p as a new one after.
// This saves having to modify l itself.
int tmpval = p->value;
p->value = value;
p->next = new_node(tmpval, p->next);
} else {
// Insert new item after p
p->next = new_node(value, p->next);
}
}
A comment: it is possible the way you are using pointers is not helping the debugging process.
For example, your print_list() could be re-written like this:
void print_list(List l){
List aux;
for(aux = l; aux != NULL; aux = aux->next)
printf("Valor: %d\n", aux->value);
}
and still behave the same. It is generally good practice not to 'hide' the pointer-like nature of a pointer by including a '*' in the typedef.
For example, if you define your list like this:
typedef struct node{
int value;
struct node *next;
} List
And pass it to functions like this:
my_func(List *l, ...)
then it'll make some of these issues more apparent. Hope this helps.
There are many problems in your code:
Hiding pointers behind typedefs is a bad idea, it leads to confusion for both the programmer and the reader.
You must decide whether the initial node is a dummy node or if the empty list is simply a NULL pointer. The latter is much simpler to handle but you must pass the address of the head node to insert and delete so they can change the head node.
printlist does not need an indirect pointer, especially starting from the address of the pointer passed as an argument. Simplify by using the Node pointer directly.
in insert you correctly insert the new node before the next higher node but you should then return from the function. Instead, you break out of the switch and the code for appending is executed, replacing the inserted node with a new node with the same value and a NULL next pointer. This is the reason 5 gets removed and lost when you insert 4. Furthermore, you should pass the address of the head node so a node can be inserted before the first.
delete starts from the address of the argument. It cannot delete the head node because the pointer in the caller space does not get updated. You should pass the address of the head node.
You should avoid using C++ keywords such as new and delete in C code: while not illegal, it confuses readers used to C++, confuses the syntax highlighter and prevents compilation by C++ compilers.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *new_node(int value, Node *next_node) {
Node *node = malloc(sizeof(*node));
if (node != NULL) {
node->value = value;
node->next = next_node;
}
return node;
}
void print_list(Node *list) {
for (; list != NULL; list = list->next)
printf("Valor: %d\n", list->value);
}
void insert_node(Node **p, int value) {
while ((*p) != NULL && (*p)->value < value)
p = &(*p)->next;
*p = new_node(value, *p);
}
void delete_node(Node **p, int value) {
while (*p != NULL) {
if ((*p)->value == value) {
Node *found = *p;
*p = (*p)->next;
free(found);
// return unless delete() is supposed to remove all occurrences
return;
} else {
p = &(*p)->next;
}
}
}
int main(void) {
Node *n = NULL;
insert_node(&n, 2);
insert_node(&n, 3);
insert_node(&n, 5);
insert_node(&n, 4);
insert_node(&n, 1);
print_list(n);
delete_node(&n, 3);
print_list(n);
delete_node(&n, 1);
print_list(n);
return 0;
}
I know how pointers works.
I done similar problem with this way
deleteNode(struct node *head_ref, int key);
which is working and # here http://quiz.geeksforgeeks.org/linked-list-set-3-deleting-node/ they have used
deleteNode(struct node **head_ref, int key);
which also correct but is there reason to do so , will 1st one fails in any condition or is it bad way etc.
struct linked_list *deleteNode(struct linked_list *head, int key )
{
struct linked_list *prevNode,*current,*temp;
if( head==NULL)
return head;
if(head->data==key)
{
if(head->next==NULL)
{ free(head);
return NULL;
}
else
temp=head->next;
free(head);
return temp;
}
prevNode= head;
current=head->next;
printf("\n %d\n",(current->data));
while((current!=NULL) && (current->data!=key))
{ printf("\n here");
prevNode= current;
current=current->next;
}
if(current==NULL){
printf("\n element not present in list !\n");
return head;
}
if(current->next==NULL)
prevNode->next=NULL;
else
prevNode->next=current->next;
free(current);
return head;
}
head=deleteNode(head,key);
If you need to delete the head node, the first function won't work because you can't change the head node. The second function takes the address of the head node so it can be changed if need be.
The deleteNode function in the link contains the following:
struct node* temp = *head_ref, *prev;
// If head node itself holds the key to be deleted
if (temp != NULL && temp->data == key)
{
*head_ref = temp->next; // Changed head
free(temp); // free old head
return;
}
You can see here that it dereferences head_ref to change what it points to.
Let's forget the linked list and just think of updating a variable. There are two, equally valid ways to do it:
// 1. pass back
int update_int1(int val) {
return val + 1;
}
void caller1() {
int var = 1;
var = update_int1(var);
}
// 2. write back
void update_int2(int *val) {
*val += 1;
}
void caller2() {
int var = 1;
update_int2(&var);
}
This is easy to understand, so let's do the same thing with a pointer:
// 1. pass back
char *update_ptr1(char *ptr) {
return ptr + 1;
}
void caller1() {
char *ptr = malloc(10);
ptr = update_ptr1(ptr);
}
// 2. write back
void update_ptr2(char **ptr) {
*ptr += 1;
}
void caller2() {
char *ptr = malloc(10);
update_ptr2(&ptr);
}
It works exactly the same as for int! The key is there's always one more star if you want to write back, not pass back.
Which pattern you choose is up to you. The write-back approach is popular for linked lists.
When you write *b==>access contents of address contained in b.
When you write **c==>Access contents of contents of address contained in c.
I'm implementing a linked list and it needs to have a function that when given a head of a linked list and a cstring, it finds and deletes a node whose value is the cstring.
typedef struct node
{
char entry[21];
struct node* next;
} node;
/*returns true if node with phrase value found, otherwise false*/
bool findAndRemove(node* root, char phrase[21])
{
if(root != NULL)
{
node* previous = NULL;
while(root->next != NULL)
{
if(strcmp(root->entry, phrase) == 0)//found
{
if(previous == NULL)//node to delete is at head
{
node* tmp = root;
root = root->next;
free(tmp);
return true;
}
previous->next = root->next;
free(root);
return true;
}
previous = root;
root = root->next;
}
return false;
}
}
It works alright but when deleting the head some garbage gets printed out. What is happening and how can I fix this? Do I have any memory leaks? Out of curiosity is the term "root" or "head" more commonly used for the first node in a linked list?
The first thing to realise is that removing an element from a linked list involves changing exactly one pointer value: the pointer that points at us. This can be the external head pointer that points to the first list element, or one of the ->next pointers inside the list. In both cases that pointer needs to be changed; its new value should become the value of the ->next pointer of the node to be deleted.
In order to change some object (from within a function) we need a pointer to it. We need to change a pointer, so we will need a pointer to pointer.
bool findAndRemove1(node **ptp, char *phrase)
{
node *del;
for( ;*ptp; ptp = &(*ptp)->next) {
if( !strcmp((*ptp)->entry, phrase) ) { break; } //found
}
/* when we get here, ptp either
** 1) points to the pointer that points at the node we want to delete
** 2) or it points to the NULL pointer at the end of the list
** (in the case nothing was found)
*/
if ( !*ptp) return false; // not found
del = *ptp;
*ptp = (*ptp)->next;
free(del);
return true;
}
The number of if conditions can even be reduced to one by doing the dirty work in the loop,and returning from the loop but that would be a bit of a hack:
bool findAndRemove2(node **ptp, char *phrase)
{
for( ;*ptp; ptp = &(*ptp)->next) {
node *del;
if( strcmp((*ptp)->entry, phrase) ) continue; // not the one we want
/* when we get here, ptp MUST
** 1) point to the pointer that points at the node we want to delete
*/
del = *ptp;
*ptp = (*ptp)->next;
free(del);
return true;
}
return false; // not found
}
But what if the list is not unique, and we want to delete all the nodes that satisfy the condition? We just alter the loop logic a bit and add a counter:
unsigned searchAndDestroy(node **ptp, char *phrase)
{
unsigned cnt;
for( cnt=0 ;*ptp; ) {
node *del;
if( strcmp((*ptp)->entry, phrase) ) { // not the one we want
ptp = &(*ptp)->next;
continue;
}
/* when we get here, ptp MUST point to the pointer that points at the node we wish to delete
*/
del = *ptp;
*ptp = (*ptp)->next;
free(del);
cnt++;
}
return cnt; // the number of deleted nodes
}
Update: and a driver program to test it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct list {
struct list *next;
char entry[20];
} node;
void node_add( node **ptp, char *str)
{
node *new;
for ( ; *ptp; ptp = &(*ptp)->next) {
if (strcmp ((*ptp)->entry, str) < 0) continue;
}
new = malloc (sizeof *new);
strcpy(new->entry, str);
new->next = *ptp;
*ptp = new;
}
int main (void)
{
node *root = NULL;
unsigned cnt;
node_add (& root, "aaa" );
node_add (& root, "aaa" );
node_add (& root, "bbb" );
node_add (& root, "ccc" );
node_add (& root, "aaa" );
cnt = seachAndDestroy( &root, "bbb" );
printf("Cnt(bbb) := %u\n", cnt );
cnt = seachAndDestroy( &root, "ccc" );
printf("Cnt(ccc) := %u\n", cnt );
cnt = seachAndDestroy( &root, "aaa" );
printf("Cnt(aaa) := %u\n", cnt );
printf("Root now = %p\n", (void*) root );
return 0;
}
And the output:
plasser#pisbak:~/usenet$ ./a.out
Cnt(bbb) := 1
Cnt(ccc) := 1
Cnt(aaa) := 3
Root now = (nil)
You are changing the root inside the function, thus you need to pass a double pointer:
bool findAndRemove(node** root, char phrase[21])
{
node* iterate = *root;
if(root != NULL && *root != NULL)
{
node* previous = NULL;
while(iterate->next != NULL)
{
if(strcmp(iterate->entry, phrase) == 0)//found
{
if(previous == NULL)//node to delete is at head
{
node* tmp = iterate;
*root = iterate->next;
free(tmp);
return true;
}
previous->next = iterate->next;
free(iterate);
return true;
}
previous = iterate;
iterate = iterate->next;
}
return false;
}
}
You construct a list by pointing to the first node.
Then you delete the first node, but do not update the pointer to the list to point to the second one
Just make your function check if you are deleting the first node, and always return a pointer to the first pointer of the final list. Alternatively, instead of node *root parameter, pass node **root so you can modifiy the reference in your function (although I don't like this way of working).