Not sure why I'm getting a segmentation fault here. I'm trying to create a hash table that would have collisions and the data should be string. So I'm using a char array for the data.
Need to detect collisions at the end.
#define SIZE 20
struct DataItem
{
char data[50];
int key;
};
struct DataItem* hashArray[SIZE];
struct DataItem* dummyItem;
struct DataItem* item;
int hashCode(int key)
{
return key % SIZE;
}
void insert(int key, char data[50])
{
struct DataItem *item = (struct DataItem*) malloc(sizeof(struct DataItem));
strcpy(item->data, data);
item->key = key;
//get the hash
int hashIndex = hashCode(key);
//move in array until an empty or deleted cell
while (hashArray[hashIndex] != NULL && hashArray[hashIndex]->key != -1)
{
//go to next cell
++hashIndex;
//wrap around the table
hashIndex %= SIZE;
}
hashArray[hashIndex] = item;
}
struct DataItem* delete(struct DataItem* item)
{
int key = item->key;
//get the hash
int hashIndex = hashCode(key);
//move in array until an empty
while (hashArray[hashIndex] != NULL)
{
if (hashArray[hashIndex]->key == key)
{
struct DataItem* temp = hashArray[hashIndex];
//assign a dummy item at deleted position
hashArray[hashIndex] = dummyItem;
return temp;
}
//go to next cell
++hashIndex;
//wrap around the table
hashIndex %= SIZE;
}
return NULL;
}
int detect_collisions()
{
int i = 0;
int collision = 0;
for (i = 0; i < SIZE; i++)
{
if (hashArray[i] != NULL)
{
if (hashArray[i]->key == hashArray[i + 1]->key)
;
collision++;
}
}
return collision;
}
void display()
{
int i = 0;
for (i = 0; i < SIZE; i++)
{
if (hashArray[i] != NULL)
{
printf("Phli dafa: %d\n", i);
printf(" (%d,%s)", hashArray[i]->key, hashArray[i]->data);
}
else
printf(" ~~ ");
}
printf("\n");
}
int main()
{
dummyItem = (struct DataItem*) malloc(sizeof(struct DataItem));
strcpy(dummyItem->data, NULL);
dummyItem->key = -1;
insert(1, "check");
display();
delete(item);
}
You have a problem here:
strcpy(dummyItem->data,NULL);
as strcpy will dereference a NULL pointer.
To put in an empty string use:
strcpy(dummyItem->data, "");
Your second problem is:
delete(item);
item is NULL at this point. So here:
struct DataItem* delete(struct DataItem* item)
{
int key = item->key;
^^^^^^
you dereference a NULL pointer.
Maybe your delete function should rather be:
struct DataItem* delete(int key)
{
The third problem is here (there are actually 3 problems here):
for (i = 0; i < SIZE; i++)
{
if (hashArray[i] != NULL)
{
if (hashArray[i]->key == hashArray[i + 1]->key)
^^^^^^^^^^^^^^^^
a) May be NULL
b) Out of range when i == size-1
;
^^^
c) Delete this
collision++;
}
}
My guess is that you want:
for (i = 0; i < SIZE-1; i++) // Notice
{
if (hashArray[i] != NULL && hashArray[i + 1] != NULL) // Notice
{
if (hashArray[i]->key == hashArray[i + 1]->key)
{
collision++;
}
}
}
The problem is
strcpy(dummyItem->data, NULL);
It will try to copy a string pointed by NULL (that is not pointing a string..) to your array. So it invokes Undefined Behavior
What you want (I guess) is
memset(dummyItem->data, 0x00, sizeof(dummyItem->data));
or
dummyItem->data[0] = 0x00;
or
dummyItem->data[0] = '\0';
Take also note that you must always check malloc return value: it can fail returning NULL
dummyItem = malloc(sizeof(struct DataItem));
if ( dummyItem != NULL)
{
// YOUR STUFF
}
You have also a ; just after
if (hashArray[i]->key == hashArray[i + 1]->key)
remove it.
Last thing I can see
delete(item);
is UB because of item is not initialized because the code in insert function uses a local variable, maybe you want change
struct DataItem *item = (struct DataItem*) malloc(sizeof(struct DataItem));
to
item = malloc(sizeof(struct DataItem));
EDIT 1
You are also accessing the array out of bounds with
if (hashArray[i]->key == hashArray[i + 1]->key)
hashArray[i + 1] is out of bounds when i = SIZE-1
Moreover hashArray[i + 1] can be NULL or not initialized.
If you compile your code with debugging turned on ( ie -g option with gcc ) and then run it in a debugger it will tell you what lines the seg faults are happen on. There are two places that are causing a seg fault that I can see - the strcpy being passed a NULL and also the call to delete(item) where item is still NULL. Presumably because you think you're using the one defined in insert rather than the globally defined one.
Related
Goal is to read a web page, store all words in a trie with each node containing one letter and a count of the number of characters, print the words and number of occurrences. I keep getting a segmentation fault and I think the issue is in one of these functions. Thanks!
struct trieNode *indexPage(const char *url) {
if (url == NULL) {
return NULL;
printf("Web link must be provided.");
}
//get text from page and check return value
char *page = NULL;
int bytesRead = getText(url, page, MAX_BUFFER_SIZE);
if (page == NULL) {
printf("Page could not be indexed.");
return NULL;
}
//index buffer into separate words
int i = 0;
char *word = NULL;
struct trieNode *node = malloc(sizeof(struct trieNode));
if (node == NULL) {
printf("Node memory could not be allocated.");
return NULL;
}
while (i < bytesRead) {
while (isalpha(page[i])) {
word[i] = page[i];
}
addWordOccurrence(word, sizeof(word), i);
i++;
}
return node;
}
//Create space for node in heap and add to trie structure
int addWordOccurrence(const char* word, const int wordLength, int index) {
if (word == NULL)
return -1;
//allocate memory for new node
struct trieNode *node = malloc(sizeof(struct trieNode));
if (node == NULL) {
printf("Node memory could not be allocated.");
return -2;
}
//recursively add characters to trie and
//increase count
if (index < wordLength) {
setNodeData(node->child[index], word[index]);
node->count++;
}
addWordOccurrence(word, wordLength, index + 1);
return 0;
}
Using gdb I found the fault may be coming from the print function, possibly when trying to access pointers.
//Prints contents
void printTrieContents(struct trieNode *root) {
//if child is found with a non zero count
//add child character to string
char *word = NULL;
for (int i = 0; i < SIZE; i++) {
if ((root->count) && (root->child[i])) {
word[i] = i + 'a';
printTrieContents(root->child[i]);
}
}
if (root->child == NULL) {
printf("%s: %d", word, root->count);
}
}
There are multiple issues:
in indexPage, while (isalpha(page[i])) { word[i] = page[i]; } is potentially an infinite loop.
in printTrieContents, word[i] = i + 'a' dereferences a null pointer as word is never allocated.
addWordOccurrence always recurses, even after reaching the last character. There is no need for recursion, use a loop and a proper test.
more algorithmic issues: the code needs a lot a work.
superficially, it looks like addWordOccurrence(word, sizeof(word), i); should be addWordOccurrence(word, sizeof(word), 0); - the last parameter being the index of each letter that is handled in the recursion.
I'm creating a table with linked lists where the data is duplicated when it is passed to the insertion methods.
To test this, I create an array with the values that I will insert and then insert them into the table. When I free the array and then free the table, I receive a SEG FAULT error. As such, I have concluded that the pointers in both structures must be pointing to the same memory region. However, as I duplicate the data, I cannot see where the problem could be coming from...
Here is the code for the test:
for(i=0; i<1024; i++) {
key[i] = (char*)malloc(16*sizeof(char));
sprintf(key[i],"a/key/b-%d",i);
data[i] = data_create2(strlen(key[i])+1,strdup(key[i]));
table_put(table,key[i],data[i]);
}
assert(table_size(table) == 1024);
result = (table_size(table) == 1024);
for(i=0; i<1024; i++) {
d = table_get(table,key[i]);
assert(d->datasize == data[i]->datasize);
assert(memcmp(d->data,data[i]->data,d->datasize) == 0);
assert(d->data != data[i]->data);
result = result && (d->datasize == data[i]->datasize &&
memcmp(d->data,data[i]->data,d->datasize) == 0 &&
d->data != data[i]->data);
data_destroy(d);
}
for(i=0; i<1024; i++) {
free(key[i]);
//data_destroy(data[i]);
}
table_destroy(table);
When I uncomment that data_destroy(data[i]) line, the program gives the Seg Fault.
The code for the table_put:
int table_put(struct table_t *table, char * key, struct data_t *value) {
if(table == NULL || key == NULL || value == NULL) return -1;
struct entry_t *new_pair = entry_create(key, value);
int i = key_hash(key, table->size);
int l = 0;
if (list_get(table->list[i], new_pair->key) == NULL) {
l = 1;
}
if(list_add(table->list[i], new_pair)==-1){
entry_destroy(new_pair);
return -1;
}
table -> length = table -> length + l;
return 0;
}
The code for: entry_create, where I duplicate the data:
struct entry_t *entry_create(char *key, struct data_t *data){
if(data == NULL || key == NULL){
return NULL;
}
struct entry_t *entry = (struct entry_t *) malloc(sizeof(struct entry_t));
if(entry == NULL){
return NULL;
}
entry->key = (char*) malloc(sizeof(strlen(key))+1);
memcpy(entry->key,key,strlen(key)+1);
entry->value = data_dup(data);
//free(key);
data_destroy(data);
return entry;
}
segfaults on free are usually double free's means that you've tried to free something that's already been free'd . or when you try to free pointer with out any malloc.
is there any malloc on data_create2 function ?
if there is not it is the case you are trying to free data array members that where never malloc'd
I am assigning an int pointer a value pulled from sscanf. I then want to pass it in to a method from a different file, counters_add. Although I can print out the value stored in the pointer and its address, as soon as I pass it to this method the program throws a seg fault. From testing I know that the program does not even get inside this method before seg faulting.
This method takes parameters of (counters_t *ctrs, const int key). The counters_t object is a struct I have defined earlier in the file.
I don't prematurely free anything and have verified that neither ctrs nor key are NULL. Why am I getting a segmentation fault?
int *key = malloc(sizeof(int));
//check if key is null here
sscanf(line, "%i", key);
printf("key: %i\n", *key); //this prints out the value
printf("key: %p\n", (void *)key); //this prints out the address
counters_add(ctrs, *key);//seg fault here, without even getting inside of method
Initialization of ctrs:
counters_t *ctrs = count_malloc(sizeof(counters_t));
if (ctrs == NULL) {
return NULL; // error allocating set
} else {
// initialize contents of set structure
ctrs->head = NULL;
}
The rest of the code:
void
counters_add(counters_t *ctrs, const int key)
{
if (key >= 0 && ctrs != NULL) {
// allocate a new node to be added to the list if the key is not already in the set
if(counters_get(ctrs,key) == 0) {//if it doesnt already exist
printf("after first if statement");
counternode_t *new = counternode_new(&key);//create it
printf("aftermaking new node");
new->next = ctrs->head;//add it to the head of the list
ctrs->head = new;
} else {
// increment the count
for(counternode_t *curr = ctrs->head; curr != NULL; curr = curr->next){
if (*(curr->key) == key){
*(curr->count) = *(curr->count) + 1;
}
}
}
}
}
int
counters_get(counters_t *ctrs, const int key)
{
printf("in counters_get");
if (ctrs == NULL) {
return 0; // null counter
} else if (ctrs->head == NULL) {
return 0; // set is empty
}//remove this in set
else {
for(counternode_t *curr = ctrs->head; curr != NULL; curr = curr->next)
{
if (*(curr->key) == key)
return *(curr->count);
printf("in loop");
}
return 0;
}
}
static counternode_t // not visible outside this file
*counternode_new(const int *key)
{
counternode_t *node = count_malloc(sizeof(counternode_t));
int *newkey = (int*)malloc(sizeof(int));
newkey = (int*) memcpy(newkey, key, (50 * sizeof(char)));
//make sure key is not over 50 ints
if (node == NULL || newkey == NULL) {
// error allocating memory for node or new key; return error
return NULL;
} else {
node->key = newkey;
*(node->count) = 1;
node->next = NULL;
return node;
}
}
Here is the counters struct:
typedef struct counters {
struct counternode *head; // head of the list of items in set
} counters_t;
here is the countersnode:
typedef struct counternode {
int *key;
int *count; //pointer to counter for this node
struct counternode *next; // link to next node
} counternode_t;
I see the problem in counternode_new:
static counternode_t // not visible outside this file
*counternode_new(const int *key)
{
counternode_t *node = count_malloc(sizeof(counternode_t));
int *newkey = (int*)malloc(sizeof(int));
newkey = (int*) memcpy(newkey, key, (50 * sizeof(char)));
...
}
In counters_add you pass to counternode_new a pointer to the variable d.
Then in counternode_new you want to copy in newkey 50 bytes with key as
the source. But key is pointer to a single integer, so you are reading 49
bytes out of bound, this leads to undefined behaviour which may lead to a
segfault. Also you are only allocating space for a single int for newkey. Besides, you are copying 50 bytes, not 50 integers. I don't get where the 50 comes from.
So your counternode_new call in counters_add makes no sense, first you have to
allocate space for a int[50] array and pass that to counternode_new.
I notice that newkey is having only sizeof(int) allocated, whereas you seem to copying 50 bytes to newkey.
int *newkey = (int*)malloc(sizeof(int));
newkey = (int*) memcpy(newkey, key, (50 * sizeof(char)));
typedef struct node {
int num_children;
struct node *children[ALPHABET_LENGTH];
} trie_node;
void add(char* a, trie_node* node){//need to make sure a is not NULL at beginning
trie_node* newNode;
int i;
if (a != NULL && node->children[(int)a[0] - 97] == NULL)
{
node->num_children++;
//initialize the children array
for (i = 0; i < ALPHABET_LENGTH; i++)
{
if (newNode->children[i] != NULL)
{
newNode->children[i] = NULL;
}
}
newNode -> num_children = 0;
a++;
add(a, newNode);
}
else if (a != NULL && node->children[(int)a[0] - 97] != NULL){
a++;
node->num_children++;
add(a, node->children[(int)a[0] - 97]);
} else{//a == NULL, which means end of the add procedure
return;
}
}
int main()
{
char* s = "add abc";
trie_node* contacts;
add(s,contacts);
return 0;
}
When I intialize the struct trie_node in main function, I can access all member of contacts. However, when I do that in my add function, the newNode doesn't work. I cannot access members like num_children under newNode. How could I fix that if I want to add a new node to the contacts
You don't allocate any stoarge to contacts or set it to NULL in main or test if it is null in add.
If you are lucky, because you are right at the start of the program, contacts is NULL when you pass it in, so the if test at the top of add crashes with a segmentation violation.
Also, you use newNode without allocating space to it.
I am writing a function called check that compares the alphabetical string of a dictionary that is loaded in through the command line with a text that is also loaded in through the command line. The function is part of a larger function called speller that acts as a spell checker.
I ran several printf debugging tests to check if the words being compared in the strcmp function. The problem comes here. The function finds that all words in the text are incorrectly spelled even when the printf test shows that the strings from the dictionary and the text are the same.
Don't know where to go from this point so any help would be greatly appreciated. Thanks so much
Below is the code for the particular function. Thanks again.
typedef struct node {
char word[LENGTH + 1];
struct node *next;
} node;
node *hashtable[27];
/* Returns true if word is in dictionary else false. */
int hash_fun (const char key);
bool check (const char *word)
{
//case-desensitizing
char caseless[strlen (word)];
int i, length;
for (int head = 0; head < 26; head++) {
hashtable[head] = NULL;
}
for (i = 0, length = strlen (word); i < length; i++) {
//("%c\n",word[i]);
if (isupper (word[i])) {
caseless[i] = tolower (word[i]);
} else {
caseless[i] = word[i];
}
}
caseless[i] = '\0';
//printf("-%s %s- \n*",word, caseless);
int word_index = hash_fun (caseless);
//printf("%i", word_index);
node *new_node = malloc (sizeof (node));
if (new_node == NULL) {
return 2;
}
if (word_index >= 0) {
if (hashtable[word_index] == NULL) {
hashtable[word_index] = new_node;
new_node->next = NULL;
}
node *cursor = malloc (sizeof (node));
cursor = hashtable[word_index];
while (cursor != NULL) {
//printf("Dictionary:%s and Text:%s \n", cursor->word, caseless);
int found;
found = strcmp (caseless, cursor->word);
if (found == 0) {
return true;
}
cursor = cursor->next;
}
}
return false;
}