I have developed the below hash table implementation code, but it fails to execute while trying to insert key,value pair.
I am very new to this concept and trying hard to fix this one.Any help would be greatly appreciated.
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include<conio.h>
struct entry_s {
char *key;
char *value;
struct entry_s *next;
};
typedef struct entry_s entry_t;
struct hashtable_s {
int size;
struct entry_s **table;
};
typedef struct hashtable_s hashtable_t;
/* Create a new hashtable. */
hashtable_t *ht_create( int size ) {
hashtable_t *hashtable = NULL;
int i;
if( size < 1 ) return NULL;
/* Allocate the table itself. */
if( ( hashtable = malloc( sizeof( hashtable_t ) ) ) == NULL ) {
return NULL;
}
/* Allocate pointers to the head nodes. */
if( ( hashtable->table = malloc( sizeof( entry_t * ) * size ) ) == NULL ) {
return NULL;
}
for( i = 0; i < size; i++ ) {
hashtable->table[i] = NULL;
}
hashtable->size = size;
return hashtable;
}
/* Hash a string for a particular hash table. */
int ht_hash( hashtable_t *hashtable, char *key ) {
unsigned long int hashval=0;
int i = 0;
/* Convert our string to an integer */
while( hashval < ULONG_MAX && i < strlen( key ) ) {
hashval = hashval << 8;
hashval += key[ i ];
i++;
}
return hashval % hashtable->size;
}
/* Create a key-value pair. */
entry_t *ht_newpair( char *key, char *value ) {
entry_t *newpair=NULL;
if( ( newpair == malloc( sizeof( entry_t ) ) ) == NULL ) {
return NULL;
}
if( ( newpair->key = _strdup( key ) ) == NULL ) {
return NULL;
}
if( ( newpair->value = _strdup( value ) ) == NULL ) {
return NULL;
}
newpair->next = NULL;
return newpair;
}
/* Insert a key-value pair into a hash table. */
void ht_set( hashtable_t *hashtable, char *key, char *value ) {
int bin = 0;
entry_t *newpair = NULL;
entry_t *next = NULL;
entry_t *last = NULL;
bin = ht_hash( hashtable, key );
next = hashtable->table[ bin ];
while( next != NULL && next->key != NULL && strcmp( key, next->key ) > 0 ) {
last = next;
next = next->next;
}
/* There's already a pair. Let's replace that string. */
if( next != NULL && next->key != NULL && strcmp( key, next->key ) == 0 ) {
free( next->value );
next->value = _strdup( value );
/* Nope, could't find it. Time to grow a pair. */
} else {
newpair = ht_newpair( key, value );
/* We're at the start of the linked list in this bin. */
if( next == hashtable->table[ bin ] ) {
newpair->next = next;
hashtable->table[ bin ] = newpair;
/* We're at the end of the linked list in this bin. */
} else if ( next == NULL ) {
last->next = newpair;
/* We're in the middle of the list. */
} else {
newpair->next = next;
last->next = newpair;
}
}
}
/* Retrieve a key-value pair from a hash table. */
char *ht_get( hashtable_t *hashtable, char *key ) {
int bin = 0;
entry_t *pair;
bin = ht_hash( hashtable, key );
/* Step through the bin, looking for our value. */
pair = hashtable->table[ bin ];
while( pair != NULL && pair->key != NULL && strcmp( key, pair->key ) > 0 ) {
pair = pair->next;
}
/* Did we actually find anything? */
if( pair == NULL || pair->key == NULL || strcmp( key, pair->key ) != 0 ) {
return NULL;
} else {
return pair->value;
}
}
int main( int argc, char **argv ) {
hashtable_t *hashtable = ht_create( 65536 );
ht_set( hashtable, "key1", "john" );
ht_set( hashtable, "key2", "kris" );
ht_set( hashtable, "key3", "ricky" );
ht_set( hashtable, "key4", "mike" );
printf( "%s\n", ht_get( hashtable, "key1" ) );
printf( "%s\n", ht_get( hashtable, "key2" ) );
printf( "%s\n", ht_get( hashtable, "key3" ) );
printf( "%s\n", ht_get( hashtable, "key4" ) );
return 0;
}
Change
newpair == malloc( sizeof( entry_t ) ) to
newpair = malloc( sizeof( entry_t ) )
in ht_newpair
Related
For some reason the data I have added to my linked list is not printing.
It prints if I add the function PrintList right after adding or if I print it within a for loop with a set number but I want it to print after adding all the products and after breaking the while loop.
This is my code:
typedef struct SProducts
{
char *name;
struct SProducts *next;
}Products;
Products *Add(Products *list, char *file)
{
Products *el = (Products *) malloc(sizeof(Products));
if(el != NULL)
{
el->name = file;
el->next = list;
}
return el;
}
void PrintList(Products *list)
{
while(list != NULL)
{
printf("%s", list->name);
list = list->next;
}
}
int main(void){
Products *list = NULL;
char file[255];
while (fgets(file,sizeof(file),stdin) != NULL)
{
list = Add(list, file);
if (file[0] == '\n')
{
break;
}
}
PrintList(list);
}
You are always passing the same address of the first character of the local character array file.
list = Add(list, file);
So the last string that is stored in this array will be outputted for all nodes of the list.
You need to allocate dynamically a character array in each node that will store the passed string.
For example
#include <stdlib.h>
#include <string.h>
//...
Products * Add( Products *list, const char *file )
{
Products *el = malloc( sizeof( Products ) );
if ( el != NULL )
{
e1->name = malloc( strlen( file ) + 1 );
if ( e1->name != NULL ) strcpy( el->name, file );
el->next = list;
}
return el;
}
//...
while ( fgets( file, sizeof( file ), stdin ) != NULL && file[0] != '\n' )
{
file[ strcspn( file, "\n" ) ] = '\0';
Products *tmp = Add( list, file );
if ( tmp != NULL ) list = tmp;
}
Pay attention to that you need also at least write a function that will delete all the allocated memory of the list when it will not be required any more.
The function below is supposed to dequeue a structure that is made of 2 queues. Each time we dequeue the first queue, its rear needs to become the front of the second queue. Essentially moving the first element in the second queue to the first queue to be its rear. I came up with the algorithm below:
int dequeue(queue* Q1,queue* Q2){
node* temp;
if(Q1->rear=NULL){
return 0;
}
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
if(count>=3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
Q1->rear->next=Q2->front;
Q1->rear=Q1->rear->next;
Q2->front=Q2->front->next;
Q1->rear->next=NULL;
if(Q2->front=NULL){
Q2->rear=NULL;
}
count--;
return 1;
}
}
It gives a segfault at Q1->rear->next=Q2->front;
is there an alternative way to achieve this?
For starters there is a typo in the condition of the if statement
if(Q2->front=NULL){
Q2->rear=NULL;
}
You are using assignment instead of comparison.
There is also a bug in this if statement
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
q1-front after this statement
Q1->front=Q1->front->next;
can be equal to NULL. In this case you need to set also Q1->rare to NULL.
But in any case your approach with the if statements
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
if(count>=3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
//...
makes the code less clear and as it occurred error prone.
I would write the function the following way
int dequeue( queue *q1, queue *q2 )
{
int success = q1->front != NULL;
if ( success )
{
if ( q2->front != NULL )
{
q1->rear->next = q2->front;
q1->rear = q1->rear->next;
q2->front = q2->front->next;
if ( q2->front == NULL ) q2->rear = NULL;
q1->rear->next = NULL;
}
node *tmp = q1->front;
q1->front = q1->front->next;
if ( q1->front == NULL ) q1->rear = NULL;
free( tmp );
--count;
}
return success;
}
Pay attention to that it is a bad programming practice when a function depends on a global variable (I mean the variable count). You could avoid such a situation wrapping queues and the variable count in a structure.
Here is a demonstration program that shows the function in action.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
} node;
typedef struct queue
{
node *front;
node *rear;
} queue;
size_t count;
int dequeue( queue *q1, queue *q2 )
{
int success = q1->front != NULL;
if ( success )
{
if ( q2->front != NULL )
{
q1->rear->next = q2->front;
q1->rear = q1->rear->next;
q2->front = q2->front->next;
if ( q2->front == NULL ) q2->rear = NULL;
q1->rear->next = NULL;
}
node *tmp = q1->front;
q1->front = q1->front->next;
if ( q1->front == NULL ) q1->rear = NULL;
free( tmp );
--count;
}
return success;
}
int push( queue *q, int data )
{
node *new_node = malloc( sizeof( node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = NULL;
if ( q->rear == NULL )
{
q->front = new_node;
}
else
{
q->rear->next = new_node;
}
q->rear = new_node;
++count;
}
return success;
}
int empty( const queue *q )
{
return q->front == NULL;
}
int front( queue *q )
{
return q->front->data;
}
int main( void )
{
queue q1 = { .front = NULL, .rear = NULL };
queue q2 = { .front = NULL, .rear = NULL };
const int N = 10;
for ( int i = 0; i < N; i++ )
{
if ( i < N / 2 ) push( &q1, i );
else push( &q2, i );
}
while ( !empty( &q1 ) )
{
printf( "%d ", front( &q1 ) );
dequeue( &q1, &q2 );
}
putchar( '\n' );
for ( int i = 0; i < N; i++ )
{
if ( i < N / 2 ) push( &q1, i );
else push( &q2, i );
}
while ( !empty( &q1 ) )
{
printf( "%d ", front( &q1 ) );
dequeue( &q1, &q2 );
}
putchar( '\n' );
}
The program output is
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
There are the same code is executed two times to show that the function dequeue works correctly.
I am trying to delete a node from a linked list but I am still new to the concept of double pointers so I tried using a global variable to hold the head pointer instead. However, I get the wrong results when I try to print my list after deleting the middle node.
I saw this question
deleting a node in the middle of a linked list and I don't know how is my delete node function different from the answer.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char u8;
typedef struct Node node;
void addfirstnode( u8 );
void addnode( u8 );
void print( void );
void deletenode( u8 key );
void deleteonlynode();
void deletefirstnode();
struct Node
{
u8 x;
node *next;
};
node *head;
u8 length = 0;
void main( void )
{
u8 x;
printf( "\nTo add node enter 0\nTo print linked list enter 1\nTo exit press 2\nTo delete node press 3\nYour Choice:" );
scanf( "%d", &x );
if ( x == 2 )
{
printf( "\nThank You\nGood Bye" );
}
while ( x != 2 )
{
switch ( x )
{
u8 n;
u8 key;
case 0: //Add node
printf( "\nPlease enter first value:" );
scanf( "%d", &n );
if ( length == 0 )
{
addfirstnode( n );
//printf("%d",head->x);
}
else
{
addnode( n );
}
printf( "\nNode added , Thank you\n" );
break;
case 1: //Print
print();
break;
case 3: //DeleteNode
printf( "\nPlease enter value to be deleted:" );
scanf( "%d", &key );
deletenode( key );
//deletefirstnode();
break;
default:
printf( "\nInvalid Choice please try again\n" );
}
printf( "\nTo add node enter 0\nTo print linked list enter 1\nTo exit press 2\nTo delete node press 3\nYour Choice:" );
scanf( "%d", &x );
if ( x == 2 )
{
printf( "\nThank You\nGood Bye" );
}
}
//where do I use free();
}
void addfirstnode( u8 n )
{
head = ( node * ) malloc( sizeof( node ) );
head->next = NULL;
head->x = n;
length++;
}
void addnode( u8 n )
{
node *last = head;
while ( ( last->next ) != NULL )
{
last = last->next;
}
last->next = ( node * ) malloc( sizeof( node ) );
( last->next )->next = NULL;
( last->next )->x = n;
length++;
}
void print( void )
{
node *last = head;
u8 count = 1;
printf( "\n---------------------" );
if ( last == NULL )
{
printf( "\nList is empty" );
}
while ( last != NULL )
{
printf( "\nNode Number %d = %d", count, last->x );
last = last->next;
count++;
}
printf( "\n---------------------" );
printf( "\n" );
}
void deletenode( u8 key )
{
node *last = head;
//node*postlast = NULL;
if ( ( last->x == key ) && ( last->next == NULL ) )
{
deleteonlynode();
}
else
{
while ( last != NULL )
{
if ( ( last->x ) == key )
{
printf( "value to be deleted is found" );
node *temp = last->next;
last->next = last->next->next;
free( temp );
length--;
}
last = last->next;
}
}
}
void deleteonlynode()
{
printf( "\n Deleting the only node" );
free( head );
head = NULL;
length--;
}
void deletefirstnode()
{
printf( "\n Deleting the first node" );
node *temp = head;
head = head->next;
free( temp );
length--;
}
The code is removing the wrong item from the linked list:
See:
if ( ( last->x ) == key )
{
printf( "value to be deleted is found" );
node *temp = last->next; // last->next? No, just last.
last->next = last->next->next;
free( temp );
length--;
}
last is pointing at the element to be removed. But then the code assigns temp to point at last->next (NOT last), and then cuts that from the list.
So by looking at node->next rather than the current node, it's possible to trim it out since you're starting from the pointer before the one to remove. Basically your code was almost there already.
void deletenode( u8 key )
{
node *ptr = head;
if ( ( ptr->x == key ) )
{
// Delete the first/head element
node *temp = ptr;
head = head->next;
free( temp );
length--;
}
else
{
while ( ptr->next != NULL )
{
if ( ( ptr->next->x ) == key )
{
printf( "value to be deleted is found" );
node *temp = ptr->next;
ptr->next = ptr->next->next;
free( temp );
length--;
}
ptr = ptr->next;
}
}
}
Also I took the liberty of renaming last to ptr because it was confusing me.
EDIT: Updated to remove the head cleanly too.
Your code seems to be deleting last->next while last should be the node that matches the key.
I guess the following code may be shorter and do the deletion
node* head;
/* returns the node* the previous_node->next should be after the deletion */
node* delete_node(node* current, u8 key) {
if (current == NULL) return NULL; // deletion comes to end
if (head->x == key) {
node* temp = current->next;
free(current);
return delete_node(temp, key);
}
current->next = delete_node(current->next, key);
return current;
}
int main() {
// build the linked list
// ...
head = delete_node(head, key);
return 0;
}
However, this implement (which uses recursion instead of loop) may cause StackOverFlow if the list is too long. I had not tested if gcc would optimize the recursion out.
I have a struct declared like this
struct data
{
char * Date;
char * String;
};
struct data **RegArray = NULL;
int ArrayCount = 0;
I add new items to the array this way:
struct data **tmp = ( struct data ** )realloc( RegArray, ( ArrayCount + 1 ) * sizeof( struct data * ) );
if ( tmp == NULL )
{
printf( "\nRealloc failed!" );
return;
}
RegArray = tmp;
RegArray[ ArrayCount ] = ( struct data * )malloc( sizeof **RegArray );
if ( RegArray[ ArrayCount ] == NULL )
{
printf( "\nMalloc failed!" );
return;
}
RegArray[ ArrayCount ]->Date = _strdup( cDate );
RegArray[ ArrayCount ]->String = _strdup( cString );
ArrayCount++;
The function which compares the values:
int CompareByDate( const void *elem1, const void *elem2 )
{
//return ( ( data* )elem1 )->Date > ( ( data* )elem2 )->Date ? 1 : -1;
return strcmp( ( ( data* )elem1 )->Date, ( ( data* )elem2 )->Date );
}//CompareByDate
And finally I call qsort like this:
qsort( RegArray, ArrayCount-1, sizeof( data ), CompareByDate );
The problem is, that the data won't be sorted.
So what am I doing wrong?
Thanks!
In your qsort call and comparison function, you forget that you're dealing with an "array" of pointers. The easiest change is to not use an array of pointers:
struct data *RegArray = NULL;
/* ... */
struct data *tmp = realloc( RegArray, ( ArrayCount + 1 ) * sizeof( struct data ) );
if ( tmp == NULL )
{
printf( "\nRealloc failed!" );
return;
}
RegArray = tmp;
RegArray[ ArrayCount ].Date = _strdup( cDate );
RegArray[ ArrayCount ].String = _strdup( cString );
ArrayCount++;
This will make your qsort call (and comparison function) work as they are shown in the question.
If you don't want to change the code as outlined above, you have to change the qsort call and comparison function:
qsort( RegArray, ArrayCount-1, sizeof( data * ), CompareByDate );
/* ... */
int CompareByDate( const void *elem1, const void *elem2 )
{
struct data **d1 = (struct data **) elem1;
struct data **d2 = (struct data **) elem2;
return strcmp((*d1)->Date, (*d2)->Date);
}
I have written a program(for homework)that creates a binary search tree. It will read from a file and on each line take a string and an int. ex. I 23, where I tells the program to insert and 23 is what gets inserted. The next line would be I 45...and so on. It will perform all of the commands correctly and then output to the screen in-order, pre-order, post-order and level-order traversals. My problem is that I need to output it to a file instead and cannot for the life of me figure it out. I have tried opening another file to write to it and pass the file to each traversal function and used fprintf instead of printf but that obviously didn't work. Any help would be great!
EDIT to show file passing:
My code is as follows:
#include <stdio.h>
#include <stdlib.h>
typedef int boo;
#define TRUE 1;
#define FALSE 0;
struct tree
{
int c;
struct tree* left;
struct tree* right;
};
FILE* fo = fopen( "treedata.txt", "a+" );
//Prototypes
struct tree* create_tree( char );
struct tree* insert( struct tree*, char );
int height( struct tree* );
void print_in_order( struct tree*, FILE* );
void print_pre_order( struct tree*, FILE* );
void print_post_order( struct tree*, FILE* );
void print_level_order( struct tree*, FILE* );
void print_given_level( struct tree*, int, FILE* );
boo search_tree( struct tree*, char );
struct tree* trim_tree( struct tree*, char );
struct tree* chop_tree( struct tree* root );
int main()
{
struct tree* root = NULL;
char target;
char line[6];
char com[6];
int num;
FILE* fp = fopen( "data.txt", "r" );
if( fp )
{
while( fgets ( line, sizeof(line), fp ) != NULL )
{
sscanf(line, "%s %d", &com, &num);
if ( strcmp( com, "C" ) == 0 )
{
//root = insert( root, 0 );
create_tree( 0 );
}
else if(strcmp( com, "I" ) == 0 )
{
root = insert(root, num);
}
else if(strcmp( com, "D" ) == 0 )
{
root = trim_tree( root, num );
}
else if(strcmp( com, "F" ) == 0 )
{
if( search_tree( root , num ) )
{
fprintf(fo, "\n%d was found!\n\n", num );
}else
{
fprintf(fo, "\n%d was not found!\n", num );
}
}
else if(strcmp( com, "In" ) == 0 )
{
fprintf(fo, "In Order: \n");
print_in_order( root, fo );
fprintf(fo, "\n");
}
else if(strcmp( com, "Pr" ) == 0 )
{
fprintf(fo, "Pre-Order: \n");
print_pre_order( root, fo );
fprintf(fo, "\n");
}
else if(strcmp( com, "Po" ) == 0 )
{
fprintf(fo, "Post-Order: \n");
print_post_order( root, fo );
fprintf(fo, "\n");
}
else if(strcmp( com, "L" ) == 0 )
{
printf( "Level Order: \n");
print_level_order( root, fo );
}
}
fclose( fp );
}else
{
printf("Could not open file!!\n");
}
fclose( fo );
return 0;
}
//Functions
struct tree* create_tree( int c )
{
struct tree* temp_tree = ( struct tree* ) malloc ( sizeof( struct tree ) );
temp_tree->c = c;
temp_tree->left = NULL;
temp_tree->right = NULL;
return temp_tree;
}
struct tree* insert( struct tree* t, int c)
{
if( t == NULL )
{
return create_tree( c );
}else
{
if( c <= t->c )
{
t->left = insert( t->left, c );
}else
{
t->right = insert( t->right, c );
}
return t;
}
}
void print_in_order( struct tree* t, FILE* fo ) //print in order traversal
{
if( !t )
{
return;
}
print_in_order( t->left );
fprintf(fo, "%d\n", t->c );
print_in_order( t->right );
}
void print_pre_order( struct tree* t, FILE* fo ) //print pre order traversal
{
if( !t )
{
return;
}
fprintf(fo, "%d\n", t->c );
print_pre_order( t->left );
print_pre_order( t->right );
}
void print_post_order( struct tree* t, FILE* fo ) // print post order traversal
{
if( !t )
{
return;
}
print_post_order( t->left );
print_post_order( t->right );
fprintf(fo, "%d\n", t->c );
}
int find_height(struct tree* t)
{
if ( t == NULL )
return 0;
else
{
int lheight = find_height(t->left);
int rheight = find_height(t->right);
if (lheight > rheight)
return(lheight+1);
else return(rheight+1);
}
}
void print_given_level( struct tree* t, int level, FILE* fo )
{
if(t == NULL)
return;
if( level == 1 )
fprintf(fo, "%d\n", t->c );
else if( level > 1 )
{
print_given_level(t->left, level-1);
print_given_level(t->right, level-1);
}
}
void print_level_order( struct tree* t, FILE* fo ) //print level order traversal
{
int h = find_height(t);
int i;
for( i = 1; i <= h ; i++ )
print_given_level( t, i, fo );
}
boo search_tree( struct tree* root, char target ) //find leaf
{
if( !root )
{
return FALSE;
}else if( target < root->c )
{
return search_tree( root->left, target );
}else if( target > root->c )
{
return search_tree( root->right, target );
}else
{
return TRUE;
}
}
struct tree* trim_tree( struct tree* root, char target ) //delete leaf
{
struct tree* p;
struct tree* p2;
if( !root )
{
return NULL;
}
if( root->c == target )
{
if( root->left == root->right )
{
free( root );
return NULL;
}else if( root->left == NULL )
{
p = root->right;
free( root );
return p;
}else if( root->right == NULL )
{
p = root->left;
free( root );
return p;
}else
{
p2 = root->right;
p = root->right;
while( p->left )
{
p = p->left;
}
p->left = root->left;
free( root );
return p2;
}
}else if( root->c < target )
{
root->right = trim_tree( root->right, target );
}else
{
root->left = trim_tree( root->left, target );
}
return root;
}