Segmentation Fault in a BST of strings - c

So, I'm doing an assignment for a class in college and the objective is to construct a BST of strings that read a text, divides it and insert each word in the Tree.
But I'm getting a segmentation fault when trying to insert a word (manually), can you guys show me where I did wrong and suggest a repair?
/* Structure for the node */
typedef struct node {
char *key;
int multi;
struct node *left, *right;
} node;
node *root;
void Insert(char *x, node *p){
p = root;
/* if the pointer points to null, create a new node and insert the key */
if (*p == NULL){
(*p) = (node)malloc(sizeof(node))
(*p)->key = strcpy((*p)->key, x);
(*p)->left = NULL;
(*p)->right = NULL;
return;
}
else if (strcasecmp(x, p->key) < 0)
{
Insert(x, &p->left);
return;
}
else if (strcasecmp(x, p->key) > 0)
{
Insert(x, &p->right);
return;
}
/* if the words are equal, add 1 to the multi (how many times the word appears */
else
(*p)->multi = multi + 1;
}

This is the problematic statement: (*p)->key = strcpy((*p)->key, x); You allocated memory only for node but the pointer key is still uninitialized. You need to allocate memory for key also, something like (*p)->key = malloc(strlen(x) + 1);.

Related

strcpy() to copy string from struct member to char array is failing. Why?

I have a structure node which is used to create a binary search tree. Inside each node I am storing a integer KEY and a corresponding string value. I am performing some searches within the tree and wish to return arrays containing key value pairs of only specific nodes.
TO do so I am passing arrays by reference and saving the integer KEY to that array. This works fine, however when I try to the the same with the string I am getting poor results.
In the below code I am trying to copy the string inside root[count].value; to p_value_arr[*p_unique_count] which is a char array.
Struct definition:
typedef struct node {
int KEY;
char *value;
int node_count;
struct node *left, *right;
int unique_count;
} node;
Function to traverse graph and copy unique key value pairs. KEY is being copied correctly to an array while value is not.
void unique_key(node *root, int *p_unique_count, int p_unique_arr[], char *p_value_arr[]) {
int count = 0;
//unique *temp = (unique *)malloc(n * sizeof(unique));
if (root != NULL)
{
unique_key(root->left, p_unique_count, p_unique_arr, p_value_arr);
if (root->node_count == 1) {
root[count].unique_count = *p_unique_count;
p_unique_arr[*p_unique_count] = root[count].KEY;
printf("%s\n", root[count].value);
//"warning: assignment makes integer from pointer without a cast"
strcpy(p_value_arr[*p_unique_count],root[count].value);
printf("%d(%d) -> %s %d\n", root->KEY, root->node_count, root->value, root->unique_count);
(*p_unique_count)++;
count++;
}
unique_key(root->right, p_unique_count, p_unique_arr, p_value_arr);
}
}
A utility function to insert a new node with given key in BST
node* insert_node(node* node, int key, char *value)
{
/* If the tree is empty, return a new node */
if (node == NULL)
return newNode(key,value);
// If key already exists in BST, icnrement count and return
if (key == node->KEY)
{
(node->node_count)++;
// return node;
}
/* Otherwise, recur down the tree */
if (key < node->KEY)
node->left = insert_node(node->left, key, value);
else
node->right = insert_node(node->right, key, value);
/* return the (unchanged) node pointer */
return node;
}
node *newNode(int KEY, char *value)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->KEY = KEY;
strcpy(temp->value, value);
temp->left = temp->right = NULL;
temp->node_count = 1;
return temp;
}
Main driver code
int main() {
int unique_count = 0;
int in_count = 0;
int unique_arr[10]; /
char *value_arr[10]; // an array of pointers
/* Let us create following BST. Passing values along with key */
node *root = NULL;
//this is for storing commands
root = insert_node(root, 2, "Hello");
root = insert_node(root, 3, "Thanks");
printf("\nkeys of the given tree \n");
unique_key(root, &unique_count, unique_arr, *value_arr);
for(int i = 0; i < 10; i++) {
printf("%d %s\n", unique_arr[i], value_arr[i]); //Mismatching the argument type "char" and conversion specifier "s" and nothing prints here
}
}
Output:
Hello
keys of the given tree
Segmentation fault
Any suggestions on how I can effectively copy a string inside a struct member to an array of chars?
EDIT:
Full code: https://pastebin.com/CB4Gp0gY
Since char *value_arr[10]; is an array of pointers I followed chapter 5.6 of K&R The C programming language to pass the array of pointers to the function. I get no warnings now, but the seg fault persists.
I also have more warnings set on my NetBeans 8.2.
Output from debugger:
/cygdrive/C/Users/****/AppData/Roaming/NetBeans/8.2/bin/nativeexecution/dorun.sh: line 71: 16516 Segmentation fault (core dumped) sh "${SHFILE}"
Gonna follow up for Lundin here
node *newNode(int KEY, char *value)
{
// Allocate a new overall structure
struct node *temp = (struct node *)malloc(sizeof(struct node));
//Copy the integer key
temp->KEY = KEY;
// uh oh - copy the given string into a random location in memory and segfault.
// Hint - you need to allocate enough memory to hold the incoming string.
// Advanced hint - If you don't want to make a copy of the string, you can
// just store its pointer, but it would want to be marked constant at the least...
strcpy(temp->value, value);
// Set tree stuff and count, but we are already dead...
temp->left = temp->right = NULL;
temp->node_count = 1;
return temp;
}
Also,
printf("%d %s\n", unique_arr[i], value_arr[i]); //Mismatching the argument type "char" and conversion specifier "s" and nothing prints here
Will fail because value_arr[i] is not a string, it is a char *. For this to work, it would have to point at a valid C string, or would need to point to memory that has a properly '\0' terminated string.
Take a look at his given link as you need a deeper understanding of how C strings work.
char *value_arr[10]; // the problem is here
That initializes an array of pointers but does not assign memory to those pointers before using them for stuff like strcpy(). As per K&R chapter 5.6 one should allocate memory using alloc() for the pointer array inside the function.
If you want a pointer to point to some memory for storing a string, then you have to create such an area of memory and set the pointer to point to it.
char *p;
alloc(strlen(root[count].value) +1);
strcpy(p, root[count].value);
p_value_arr[*p_unique_count] = p;
struct node_t*curr = head;
struct node_t*node = (struct node_t*)malloc(sizeof(struct node_t));
strcpy(node -> str,str);
node -> prev = NULL;
node -> next = NULL;
if(curr == NULL)
{
head = node;
tail = node;
return
}
int value = strcmp(curr -> str,str);
if(value>0)
{
head = node;
node -> next = curr;
curr -> prev = node;
return;
}
struct node_t* prev = curr;
curr = prev -> next;
while(curr != NULL)
{
value=strcmp(prev -> str,str);
if(value < 0)
{
int value1 = strcmp(curr -> str,str)
if(value1>0)
{
node -> prev = prev;
node -> next = curr;
node -> next = node;
node -> prev = node;
}
else if(value1 == 0)
{
if(curr -> next == NULL)
tail=prev;
prev -> next = curr -> next;
curr -> prev = NULL
return;
}
}
prev = curr;
curr = prev -> next;
}
prev -> next = node;
node -> prev = prev;
tail = node;

Printing binary search tree, segmentation fault error 11

could you help me?
Program reads words from a file and puts them into binary search tree, but I get "Segmentation fault: 11" when running my print function.
struct node {
char * item;
struct node * left;
struct node * right;
};
struct node * new(char * a) {
struct node * new;
new = (struct node *)malloc(sizeof(struct node *));
new->item = a;
new->left = new->right = NULL;
return new;
}
struct node * insert(struct node * a, char * b) {
if(a == NULL) {
a = new(b);
}
else if (b <= a->item) {
a->left = insert(a->left, b);
}
else {
a->right = insert(a->right, b);
}
return a;
}
void print(struct node * a) {
if (a->left == NULL && a->right == NULL)
printf("%s", a->item);
else if (a->left != NULL)
print(a->left);
else
print(a->right);
}
from main.c :
struct node * root = NULL;
struct node * start;
start = root;
while (fscanf(fp, "%s", temp) != EOF) {
root = insert(root, temp); // insert function works ok
}
print(start);
UPDATE:
I've made a change in main.c:
int i = 0;
while (fscanf(fp, "%s", temp) != EOF) {
root = insert(root, temp);
if (!i) {
start = root;
i = 1;
}
}
Now it doesn't show error, but it prints only the last word from the tree instead of printing it recursively. Any suggestions?
UPDATE #2:
Thank you for your help. Following your suggestions I've made changes to this function:
struct node * new(char * a) {
struct node * new;
char * stringcopy;
stringcopy = malloc(strlen(a) + 1);
strcpy(stringcopy, a);
new = malloc(sizeof(* new));
new->item = stringcopy;
new->left = new->right = NULL;
return new;
}
Now everything works fine.
The original problem was almost certainly that start was NULL since you did not update it when you updated root. (Meanwhile it seems that the whole start is unnecessary; just use root directly.)
The new problem (printing only the last word) is that you are not traversing the tree correctly: your print function only prints if both left and right are NULL, so only a leaf node is ever printed, and furthermore it does not descend into the right branch if there is a left branch.
You could try something like this instead (untested code):
void print(struct node * a) {
if (a == NULL) { return; }
print(a->left);
(void) puts(a->item);
print(a->right);
}
In particular, note that if you are at a non-NULL node, you need to print its item unconditionally, or the complete output will be missing that node.
Another problem seems to be that you are not copying item when you create the node. So if your temp in insert(root, temp) is indeed a temporary object that will be overwritten or freed, all of your items (except possibly the last) will be invalid by the time you try to print them. Instead of assigning new->item = a, do the equivalent of new->item = strdup(a) and then remember to free it when you free the node.
(strdup is not in the C standard library, but it is easy to implement: allocate enough space for the string, including NUL terminator, and copy.)
Also, the comparison b <= a->item is almost certainly not doing what you expect it to; see strcmp.

Add a list on a trie node in C

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.

Segmentation fault while creating a linked list

I am writing a small program which stores data and key inside a linked list structure, and retrieves data based on a key from the user. The program also checks whether it is a unique key and if it so it stores the data by creating a node at the front of the list. But the below code throws segmentation fault all the time.
#include<stdlib.h>
/* Node having data, unique key, and next */.
struct node
{
int data;
int key;
struct node *next;
}*list='\0',*p;
/* Create a node at the front */
void storeData(int data_x,int key_x)
{
int check_key;
position *nn; //nn specifies newnode
nn=(position)malloc(sizeof(struct node));
/* Segmentation Fault occurs here */
if(list->next==NULL)
{
nn->next=list->next;
nn->data = data_x;
nn->key = key_x;
list->next = nn;
}
else
{
check_key=checkUniqueKey(key_x);
if(check_key != FALSE)
{
printf("The entered key is not unique");
}
else
{
nn->data = data_x;
nn->key = key_x;
nn->next=list->next;
list->next=nn;
}
}
}
/* Retreive data based on a key */
int retreiveData(int key_find)
{
int ret_data = NULL;
p=list->next;
while(p->next != NULL)
{
if(p->key == key_find)
{
ret_data = p->data;
break;
}
p=p->next;
}
return(ret_data);
}
/* Checks whether user key is unique */
int checkUniqueKey(int key_x)
{
int key_check = FALSE;
p=list->next;
while(p->next != NULL)
{
if(p->key == key_x)
{
key_check = TRUE;
break;
}
p=p->next;
}
return(key_check);
}
The segmentation fault occurs in the storeData function after the dynamic allocation.
There are some problems in your code:
your list handling is flawed: you always dereference the global pointer list, even before any list items are created. You should instead test if the list is empty by comparing list to NULL.
type position is not defined. Avoid hiding pointers behind typedefs, this is a great cause of confusion, which explains your mishandling of list pointers.
avoid defining a global variable with the name p, which is unneeded anyway. Define p as a local variable in the functions that use it.
NULL is the null pointer, 0 a zero integer value and \0 the null byte at the end of a C string. All 3 evaluate to 0 but are not always interchangeable.
For better portability and readability, use the appropriate one for each case.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
/* Node having data, unique key, and next */.
struct node {
int data;
int key;
struct node *next;
} *list;
/* Create a node at the front */
void storeData(int data_x, int key_x) {
if (checkUniqueKey(key_x)) {
printf("The entered key is not unique\n");
} else {
/* add a new node to the list */
struct node *nn = malloc(sizeof(struct node));
if (nn == NULL) {
printf("Cannot allocate memory for node\n");
return;
}
nn->data = data_x;
nn->key = key_x;
nn->next = list;
list = nn;
}
}
/* Retrieve data based on a key */
int retrieveData(int key_find) {
struct node *p;
int ret_data = 0;
for (p = list; p != NULL; p = p->next) {
if (p->key == key_find) {
ret_data = p->data;
break;
}
}
return ret_data;
}
/* Checks whether user key is unique */
int checkUniqueKey(int key_x) {
struct node *p;
int key_check = FALSE;
for (p = list; p != NULL; p = p->next) {
if (p->key == key_x) {
key_check = TRUE;
break;
}
}
return key_check;
}
You try to cast your address on a position structure instead of a position*
nn=(position)malloc(sizeof(struct node));
Compile your code with gcc flags -Wextra and -Wall to prevent this kind of issue.
Moreover I don't know is it is a mistake but malloc a size of struct node and your nn variable is a pointer on position.
When you initialized your list pointer you set it to NULL(as '\0'), when the program accesses address 0x00 it goes out of its boundaries and the operating system kills the process.
To avoid the segfault you can have "list" of non pointer type thus allocating on stack, when you want to access list as pointer you can do &list. Another solution would involve having variable on stack "root_node" and initialize list pointer as list = &root_node.

Pointer trouble creating binary trees

I am creating a binary tree from a bitstring in c. ie 1100100 creates a tree:
1
/ \
1 1
I decided to use a recursive function to build this tree however i keep getting the error
Debug assertion failed...
Expression : CrtIsValidHeapPointer(pUserData)
here is a fragment of my code
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
char string[1000];
int i = 0;
void insertRecursivePreorder(Node **node)
{
Node* parent = *node;
if(string[i] == '0')
{
parent = NULL;
i++;
}
else
{
Node *newn = (Node*)malloc(sizeof(Node));
newn->key = string[i];
parent = newn;
i++;
insertRecursivePreorder(&newn->left); //errors occur here
insertRecursivePreorder(&newn->right); //errors occur here
free(newn);
free(parent);
}
}
int main(void)
{
void printTree(Node* node);
Node* root = NULL;
scanf("%s", string);
insertRecursivePreorder(&root);
//... do other junk
}
i was wondering why this error comes about and what i can do to fix it.
The immediate problem is likely to be calling free on a pointer twice. In insertRecursivePreorder, you set parent to newn, and then call free on both. As an example of this, the following program fails (but works if you comment out one of the free(..)s):
#include <stdlib.h>
int main() {
int *a = malloc(sizeof(int)),
*b = a;
free(a);
free(b);
return 0;
}
However, there are several problems with your logic here. You should only call free when you have completely finished with the pointer, so if you are using your tree later you can't free it as you construct it. You should create a second function, recursiveDestroyTree, that goes through and calls free on the tree (from the bottom up!).
And, you probably want *node = newn rather than parent = newn, since the latter is the only one that actually modifies node.
(You could also change your function to return a Node * pointer, and then just go:
root = insertRecursivePreorder();
and
newn->left = insertRecursivePreorder();
newn->right = insertRecursivePreorder();
instead of trying to keep track of pointers to pointers etc.)
(Furthermore, on a stylistic point, using global variables is often bad practice, so you could have your insertRecursivePreorder take int i and char * string parameters and use them instead of global variables.)
The problem was: you were never assigning to the double pointer in 'insertRecursivePreorder', so root always stayed NULL.
#include <stdio.h>
#include <stdlib.h>
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
/* slightly changed the syntax for the str
** ; now '.' indicates a NULL pointer, values represent themselves.
*/
char *string = "12..3.." ;
/* Removed the global index 'i' */
void printTree(Node* node, int level);
unsigned insertRecursivePreorder(Node **pp, char *str);
unsigned insertRecursivePreorder(Node **pp, char *str)
{
unsigned pos =1;
if (!*str) { *pp = NULL; return 0; } /* safeguard for end of string */
if (*str == '.') { *pp = NULL; return pos; }
*pp = malloc(sizeof **pp);
(*pp)->key = *str;
pos += insertRecursivePreorder(&(*pp)->left, str+pos);
pos += insertRecursivePreorder(&(*pp)->right, str+pos);
return pos;
}
void printTree(Node* node, int level)
{
unsigned pos,len;
len = level> 0 ? level : -level;
for (pos =0; pos < len; pos++) putchar (' ');
if (!level) printf ("Root=");
else if (level<0) printf ("Left=");
else printf ("Right=");
if (!node) { printf( "Null\n" ); return; }
printf("Key=%c\n", node->key );
printTree(node->left, -(len+1) ) ;
printTree(node->right, len+1) ;
}
int main(void)
{
Node *root = NULL;
unsigned result = 0;
result = insertRecursivePreorder(&root, string);
printf( "Result=%u\n", result);
printTree(root, 0);
return 0; printTree(root, 0);
}
Output:
Result=7
Root=Key=1
Left=Key=2
Left=Null
Right=Null
Right=Key=3
Left=Null
Right=Null

Resources