how do i fix this malloc error occurred while hashing - c

trying to implement a dictionary using a hash table after a lot of debugging getting stuck with this malloc error
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* to store a data (consisting of key and value) in hash table array */
struct item
{
char key[100];
char value[1000];
};
/* each hash table item has a flag (status) and data (consisting of key and value) */
struct hashtable_item
{
int flag;
/*
* flag = 0 : data does not exist
* flag = 1 : data exists at given array location
* flag = 2 : data was present at least once
*/
struct item *data;
};
struct hashtable_item *array;
int size = 10007;
int max = 10007;
/* this function returns corresponding index of the given key */
int hashcode(char* key,int TS)
{
return (key[0]+27*key[1]+729*key[2])%TS;
}
/* this function initializes the hash table array */
void init_array()
{
int i;
for (i = 0; i < max; i++)
{
array[i].flag = 0;
array[i].data = NULL;
}
}
/* this function inserts an element in the hash table */
void insert(char* key, char* value,int TS)
{
int index = hashcode(key,TS);
int i = index;
int h = 1;
struct item *new_item = (struct item*) malloc(sizeof(struct item));
strcpy(new_item->key , key);
strcpy(new_item->value , value);
/* probing through the array until an empty space is found */
while (array[i].flag == 1)
{
if (array[i].data->key == key)
{
/* case when already present key matches the given key */
printf("\n This key is already present in hash table, hence updating it's value \n");
strcpy(array[i].data->value , value);
return;
}
i = (i + (h * h)) % max;
h++;
if (i == index)
{
printf("\n Hash table is full, cannot add more elements \n");
return;
}
}
array[i].flag = 1;
array[i].data = new_item;
printf("\n Key (%s) has been inserted\n", key);
size++;
}
/* to remove an element form the hash table array */
void remove_element(char* key,int TS)
{
int index = hashcode(key,TS);
int i = index;
int h = 1;
/* probing through the hash table until we reach at location where there had not been an element even once */
while (array[i].flag != 0)
{
if (array[i].flag == 1 && array[i].data->key == key)
{
/* case where data exists at the location and its key matches to the given key */
array[i].flag = 2;
array[i].data = NULL;
size--;
printf("\n Key (%s) has been removed \n", key);
return;
}
i = (i + (h * h)) % max;
h++;
if (i == index)
{
break;
}
}
printf("\n Key does not exist \n");
}
/* to display the contents of hash table */
void display()
{
int i;
for(i = 0; i < max; i++)
{
if (array[i].flag != 1)
{
printf("\n Array[%d] has no elements \n", i);
}
else
{
printf("\n Array[%d] has elements \n %s (key) and %s (value) \n", i, array[i].data->key, array[i].data->value);
}
}
}
int size_of_hashtable()
{
return size;
}
main function
void main()
{
int choice,n, c;
char key[100];
char value[1000];
int TS=10007;
array = (struct hashtable_item*) malloc(max * sizeof(struct hashtable_item*));
init_array();
do {
printf("Implementation of Hash Table in C with Quadratic Probing.\n\n");
printf("MENU-: \n1.Inserting item in the Hash table"
"\n2.Removing item from the Hash table"
"\n3.Check the size of Hash table"
"\n4.Display Hash table"
"\n\n Please enter your choice-:");
scanf("%d", &choice);
switch(choice)
{
case 1:
printf("Inserting element in Hash table \n");
printf("Enter key:");
fgets(key,100, stdin);
printf("Enter value:");
fgets(value,1000, stdin);
insert(key, value,TS);
break;
case 2:
printf("Deleting in Hash table \n Enter the key to delete-:");
fgets(key,100, stdin);
remove_element(key,TS);
break;
case 3:
n = size_of_hashtable();
printf("Size of Hash table is-:%d\n", n);
break;
case 4:
display();
break;
default:
printf("Wrong Input\n");
}
printf("\n Do you want to continue-:(press 1 for yes)\t");
scanf("%d", &c);
}while(c == 1);
}
Implementation of Hash Table in C with Quadratic Probing.
this is how the output looks like
MENU-:
1.Inserting item in the Hash table
2.Removing item from the Hash table
3. Check the size of the Hash table
4.Display Hash table
Please enter your choice-:1
Inserting element in Hash table
Enter key:Enter value:john helllo we aer
a.out: malloc.c:2374: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end `enter code here`& pagemask) == 0)' failed.
Aborted (core dumped)

Usually sysmalloc errors are thrown when you corrupt some memory, like writing or reading from unallocated space and etc.
The first thing I noticed is that the allocation of array is not quite correct. I figured out that you need an array of struct hashtable_item-s but you are allocating space for an array of pointers.
sizeof(struct hashtable_item*) will always be 8 in x64 systems because it's the size of a pointer. you should probably use sizeof(struct hashtable_item) it will give you the size of actual struct object.
what you need is something like this:
array = (struct hashtable_item*) malloc(max * sizeof(struct hashtable_item));
But on the other hand as your array is static I'd recommend that you allocated it in stack instead of heap:
struct hashtable_item[10007];
Also if you could provide information about at which line is your insert() failing it would be appreciated.

Related

simple patient managing program using queue

I'm making simple patient managing program using circular queue but q.rear always have "0" value while executing exit_hos()
I thought that addq() makes variable "rear" different, but It doesn't work.
is_empty() always return front and rear is same.
I think I'm misunderstanding some codes and memory concepts.
how can I fix these functions?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 50
#define MAX_QUEUE_SIZE 6
typedef struct {
char** value;
int front;
int rear;
} Queue;
void init_queue(Queue* q) {
q->value = (char**)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
q->front = 0;
q->rear = 0;
}
int is_full(Queue* q) {
if (((q->rear +1) % MAX_QUEUE_SIZE) == q->front)
return 1;
else
return 0;
}
int is_empty(Queue* q) {
if (q->front == q->rear)
return 1;
else
return 0;
}
void addq(Queue* q, char* value) {
q->rear = (q->rear+1) % MAX_QUEUE_SIZE;
q->value[q->rear] = value;
printf("addq: %s", value);
return;
}
char* deleteq(Queue* q) {
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return q->value[q->front];
}
void arrive(Queue q) {
int input;
char name[MAX_SIZE];
printf("\n");
printf("1. submit\n");
printf("2. cancel\n");
scanf("%d", &input);
if (input == 1) {
if (is_full(&q) == 1) {
printf("Service is not available\n");
}
else {
printf("name: ");
scanf("%s", name);
addq(&q, name);
}
}
else if (input == 2) {
return;
}
else {
printf("input error\n");
return;
}
return;
}
void exit_hos(Queue q) {
char patient[MAX_SIZE];
if (is_empty(&q) == 1)
{
printf("There is no patient waiting\n");
}
else {
strcpy(patient, deleteq(&q));
printf("patient: %s", patient);
}
return;
}
int main() {
int input;
Queue q;
init_queue(&q);
while (1)
{
printf("\nINPUT\n");
printf("1. Arrive hostpital\n");
printf("2. Exit hospital\n");
printf("3. service exit\n");
scanf("%d", &input);
if (input == 1)
arrive(q);
else if (input == 2) {
exit_hos(q);
}
else if (input == 3) {
printf("exit\n");
return 0;
}
else {
printf("input error\n");
}
}
free(q.value);
return 0;
}
I think that this line is wrong:
q->value = (char**)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
I think that it should be:
char * _value = (char*)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
q->value = &_value;
malloc is going to return a pointer to a char array. q->value is a pointer to a pointer to a char array. So you want to set it to the address of the char array that malloc is created for you.
Change you init_queue code to this and it will work:
void init_queue(Queue* q) {
char * _value = (char*)malloc(sizeof(char*) * MAX_QUEUE_SIZE);
q->value = &_value;
q->front = 0;
q->rear = 0;
}
Output:
Chris#DESKTOP-BCMC1RF ~
$ ./main.exe
INPUT
1. Arrive hostpital
2. Exit hospital
3. service exit
1
1. submit
2. cancel
1
name: fred
addq: fred
INPUT
1. Arrive hostpital
2. Exit hospital
3. service exit
2
If you already have a max queue size and a max size, you are better off pre-allocating the whole thing as an array, reducing memory headaches. As a general rule, avoid headaches unless they provide a feature you want.
Note: This method of keeping track of and re-using memory is called a circular buffer (not to be confused with the linked list types that are more commonly called queues).
#define MAX_SIZE 50
#define MAX_QUEUE_SIZE 6
typedef struct {
char value [MAX_QUEUE_SIZE][MAX_SIZE + 1]; //+1 to hold extra null termination
unsigned int front;
unsigned int size; //size is a clearer than rear, which could have meant end item or end+1 and needed special empty queue handling
} Queue;
void init_queue(Queue* q) {
memset(q,0,sizeof(Queue)); //just zero it all
//more info on this and some situation-dependent alternatives https://stackoverflow.com/questions/11152160/initializing-a-struct-to-0
}
int is_full(const Queue* q) {
return q->size >= MAX_QUEUE_SIZE;
}
int is_empty(const Queue* q) {
return q->size == 0;
}
//sometimes called a push operation
//return 0 if failed
int addq(Queue* q, const char* value) {
//error check, abort, error handling section:
//full queue -> abort
if(is_full(q)) return 0;
//long value -> truncate handled via strncpy
//actual operation
const unsigned int destination = (q->front + q->size) % MAX_QUEUE_SIZE;
strncpy(q->value[destination],value,MAX_SIZE);
q->size = q->size + 1;
printf("addq: %s", q->value[destination]);
return q->size;
}
//sometimes called a pop operation
//return value may not persist if addq is called, but fine for your use of copying on call
const char* deleteq(Queue* q) {
if(is_empty(q)) return 0;
const char * retval = q->value[q->front];
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
q->size = q->size - 1;
return retval;
}
also remember to use either MAX_SIZE + 1 or strncpy with MAX_SIZE - 1 since "No null-character is implicitly appended at the end of destination if source is longer than num."
(and strcpy and scanf as you sling them onto arrays is unsafe)

why i get same values inside hash table?

I created hash table to insert my values . But when I insert more than one value I got same values inside all fields . my code is here :
create a structure for both user and hashtable
struct UserNode
{
char *username;
char *password;
};
struct HashTable
{
int size;
struct UserNode *table;
};
// initialize the hash table as NULL
struct HashTable* initializeTable(int size)
{
struct HashTable *htable;
int i = 0;
if (size < MIN_TABLE_SIZE)
{
printf("Table Size Too Small\n");
return NULL;
}
htable = malloc(sizeof(struct HashTable));
if (htable == NULL)
{
printf("Out of Space\n");
return NULL;
}
htable->size = size;
htable->table = malloc(size * sizeof(struct UserNode));
if (htable->table == NULL)
{
printf("Table Size Too Small\n");
return NULL;
}
for (i = 0; i < htable->size; i++)
{
htable->table[i].username= malloc(20 * sizeof(char));
htable->table[i].password = malloc(20 * sizeof(char));
htable->table[i].username=NULL;
htable->table[i].password=NULL;
}
printf("Hsh table sucessfully created\n");
return htable;
}
insert each user name to hash table
int Insert(char *key,char *password,struct HashTable *htable)
{
int pos = 0;
pos = Find(key,htable);
printf("the value of key : %d\n",pos);
if ((htable)->table[pos].username == NULL)
{
(htable)->table[pos].username,key ;
(htable)->table[pos].password = password;
}
else
{
printf("Duplicate element ..\n");
}
return 0;
}
This function to display the hash table
void Retrieve(struct HashTable *htable)
{
int i=0;
for (i = 0; i < htable->size; i++)
{
if (htable->table[i].username == NULL)
printf("Position: %d \tusername : NULL\tpassword: NULL\n",i + 1);
else
printf("Position: %d \t username: %s\tpassword: %s\n",i + 1,htable->table[i].username,htable->table[i].password);
}
}
and I am calling these function from main function as :
............main codes............
...............................
case 1:
printf("Enter size of the Hash Table:\n");
scanf("%d",&size);
htable = initializeTable(size);
break;
case 2:
if (i > htable->size)
{
printf("Table is Full, Rehash the table\n");
continue;
}
printf("Enter the username:\n");
scanf("%s",&username);
printf("Ebter the password:\n");
scanf("%s",&password);
Insert(username,password,htable);
i++;
break;
case 3:
printf("Display\n");
Retrieve(htable);
break;
But when I insert more username and password inside structures via insert function , I got same values in both fields . that is the new one is overwrite the previous one and display both value as new username . why ? an problem on my code ?
Two things:
You have the code:
htable->table[i].username= malloc(20 * sizeof(char));
htable->table[i].password = malloc(20 * sizeof(char));
htable->table[i].username=NULL;
htable->table[i].password=NULL;
First you allocate memory, then you immediately overwrite the pointers with NULL making you loose the memory you just allocated, leading to a leak and possible undefined behavior (and probable crashes) if you use the pointers without checking for NULL.
If you are going to allocate fixed sizes for the username and password members of the UserNode structure, why not make them arrays? Like
struct UserNode
{
char username[20];
char password[20];
};
This will, incidentally, also solve the first problem since you no longer need to allocate memory. It will also lessen memory fragmentation.
In Insert(),
if ((htable)->table[pos].username == NULL)
{
(htable)->table[pos].username,key ;
(htable)->table[pos].password = password;
The (htable)->table[pos].username,key; line just did nothing. Also, strings should be copied through strcpy() or strncpy(), not through pointer assignment.
So it should be:
if (htable->table[pos].username == NULL)
{
htable->table[pos].username = malloc(strlen(key) + 1);
strcpy(htable->table[pos].username, key);
htable->table[pos].password = malloc(strlen(password) + 1);
strcpy(htable->table[pos].password, password);
}

Creating a dynamically expandable array of memory in C

In my below code I am trying to create a dynamically expandable array of memory.
#include <stdio.h>
#include <stdlib.h>
#define BLOCKSIZE 5
int hash_table_length = 0;
int *currentblock = NULL;
int size_left;
int *hash_table = NULL;
int *start = NULL;
int *create_hash_table() {
int *tmp;
if (currentblock == NULL || size_left == 0) {
if (currentblock == NULL) {
currentblock = (int *) malloc( BLOCKSIZE * sizeof(int));
start = currentblock;
size_left = BLOCKSIZE;
} else {
currentblock = (int *) malloc( BLOCKSIZE * sizeof(int));
size_left = BLOCKSIZE;
}
}
tmp = currentblock++;
size_left -= 1;
return tmp;
}
void build() {
int hash;
int i = 0;
for (i = 0; i < 20; i++) {
hash = i + 3;
if (hash_table_length == 0) {
hash_table = create_hash_table();
hash_table_length++;
} else {
hash_table = create_hash_table();
hash_table_length++;
}
hash_table = &hash;
printf("hash value is %d\n", *hash_table);
}
}
int main() {
build();
// How do I reach the start of the hash table again?
// the below start does not give me the first value
printf("Hash table first value is %d\n", *start);
return 0;
}
My problem here is I wish to traverse through the values stored in the hash_table. I am unable to reach to the first element/address of the hash_table. I wish to print out all the values stored in my hash table. How can this be done?
In your code the hash values never get stored inside the hash table(inside currentblock). Inside the create_hash_table() function you allocate memory for a new block but never store values inside this block. Thus if you try dereferencing any of these int* locations you might get a garbage value(which may be a 0).
This is what is precisely happening inside your main() function when you dereference the start pointer. It is infact pointing to the start of the hash table and as that location is uninitialized it gives an output of 0.
To actually store values inside the hash table change the following inside build():
hash_table = &hash;
to:
*hash_table = hash; // Store value of 'hash' inside the memory location pointed to by hash table(which happens to be 'current_block' inside build())
Now if you try running the code, it will output 3.
Coming to the second part of question as to how you'll traverse the entire hash table: It cannot be done using this code. This is because there is no linkage between your malloc'd blocks of integers. The malloc() call can assign any block of free memory from the heap. Thus in the current form you have disconnected blocks of locations which cannot be traversed.
Instead of malloc you can use realloc to increase the size of your current block. realloc allocates memory for the larger block and copies your previous data to this new block. This will essentially allow you to traverse the entire hash table using start.
Here is how you might do that:
#include <stdio.h>
#include <stdlib.h>
#define BLOCKSIZE 5
int hash_table_length = 0;
int *currentblock = NULL;
int size_left;
int *hash_table = NULL;
int *start = NULL;
int *create_hash_table() {
int *tmp;
if (currentblock == NULL || size_left == 0) {
if (currentblock == NULL) {
currentblock = (int *) malloc(BLOCKSIZE * sizeof(int));
start = currentblock;
size_left = BLOCKSIZE;
} else {
/* Call realloc() to allocate new memory block of size (hash_table_length+BLOCKSIZE) and copy previous data*/
currentblock = ((int *) realloc(start,(hash_table_length + BLOCKSIZE) * sizeof(int))) + hash_table_length;
size_left = BLOCKSIZE;
}
}
tmp = currentblock++;
size_left -= 1;
return tmp;
}
void build() {
int hash;
int i = 0;
for (i = 0; i < 20; i++) {
hash = i + 3;
if (hash_table_length == 0) {
hash_table = create_hash_table();
hash_table_length++;
} else {
hash_table = create_hash_table();
hash_table_length++;
}
/* Store value of hash inside the hash_table */
*hash_table = hash;
printf("hash value is %d\n", *hash_table);
}
}
int main() {
int i;
build();
printf("Hash table first value is %d\n", *start);
/* Traverse the hash table */
for(i = 0; i < hash_table_length; ++i)
printf("hash_table[%d] = %d\n",i,*start++);
return 0;
}

Seg Fault in my

I have an issue with my code here when I try to add a record to the database. Everytime I enter anything more than a few characters in for the first name prompt, the program will seg fault, even after moving elements from the old record. I understand that seg faults are due to trying to access memory that we don't have access too, but for the life of me I can't figure out what's causing it. The point of this code is to create a structure of type credit card which is defined in the header file which has a hardcoded set of 4 records, and be able to print the current database, add a record, delete a record, and other choices from the menu. Right now I am focusing on adding and deleting a record, as they are the most difficult part of this program. Why do I keep getting seg fault errors when trying to add a record?
The header file:
#ifndef myStruct
#define myStruct
struct creditCard
{
char firstName[100];
char lastName[100];
char cardNumber[17]; //TA advised to use string since 16 digits will overflow in plain integer
char expMonth[10];
};
//function headers below
int printCreditCard(struct creditCard *);
int sizeOfDb(struct creditCard *);
int countRecords(struct creditCard *);
int deleteRecord(struct creditCard *);
int addRecord(struct creditCard *);
#endif
Here is the actual program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "myStruct.h"
int accesses = 0; //number of times database was manipulated
int count = 0; //used to count how many records there are; we always start at 4
//int size = 0; //used to tell us how big the database is
struct creditCard *ptr; //chunk of memory for each record/structure
struct creditCard *headPtr; //chunk of memory for the first records/structure
int main(void)
{
ptr = (struct creditCard *) malloc(4 * sizeof(struct creditCard));
headPtr = ptr;
memcpy(ptr->firstName,"Bob",100);
memcpy(ptr->lastName,"Marley",100);
memcpy(ptr->cardNumber,"0000000000000000",17);
memcpy(ptr->expMonth,"September", 10);
ptr++;
count = count++;
memcpy(ptr->firstName, "John", 100);
memcpy(ptr->lastName, "Adams", 100);
memcpy(ptr->cardNumber,"1111111111111111",17);
memcpy(ptr->expMonth, "October", 10);
ptr++;
count = count++;
memcpy(ptr->firstName, "Bill", 100);
memcpy(ptr->lastName, "Gates", 100);
memcpy(ptr->cardNumber,"2222222222222222",17);
memcpy(ptr->expMonth, "January", 10);
ptr++;
count = count++;
memcpy(ptr->firstName, "Steve", 100);
memcpy(ptr->lastName, "Jobs", 100);
memcpy(ptr->cardNumber,"3333333333333333",17);
memcpy(ptr->expMonth, "May", 10);
count = count++;
while (1)
{
//headPtr = ptr; //put the newest database into headPtr so it points to the first record in that database
//ptr = headPtr; //start the database back at the first record
//countRecords(ptr); //update the count of the current database
int sel;
printf("MAIN MENU\n");
printf("=====\n");
printf("1. Select 1 to print all records.\n");
printf("2. Select 2 to print number of records .\n");
printf("3. Select 3 to print size of database.\n");
printf("4. Select 4 to add record.\n");
printf("5. Select 5 to delete record.\n");
printf("6. Select 6 to print number of accesses to database.\n");
printf("7. Select 7 to Exit.\n");
printf("Enter Your Selection: \n");
scanf("%d", &sel); //get user input;
if (sel == 1)
{
printCreditCard(ptr);
accesses++;
}
else if (sel == 2)
{
fprintf(stderr,"Number of records in the database is %d records\n", count); //pulls value of count from global updated variable
accesses++;
}
else if (sel == 3)
{
sizeOfDb(ptr);
accesses++;
}
else if (sel == 4)
{
ptr = headPtr;
addRecord(ptr);
accesses++;
}
else if (sel == 5)
{
deleteRecord(ptr);
accesses++;
}
else if (sel == 6)
{
fprintf(stderr,"Number of accesses to the database is %d\n", accesses);
accesses++;
}
else if (sel == 7)
{
printf("Now Exiting.\n");
return 0;
}
else
{
printf("Invalid input, please select a valid option.\n");
break; //go back to the main menu
}
}
}
//functions defined below
int sizeOfDb(struct creditCard *card2)
{
int size = 0;
int j;
for (j = 1; j <= count; j++)
{
size += sizeof(card2->firstName); //get the size of each element
size += sizeof(card2->lastName);
size += sizeof(card2->cardNumber);
size += sizeof(card2->expMonth);
card2++;
}
//loop through each record and get sizeof() of each record
fprintf(stderr, "Total Size of the Database is %d bytes.\n", size);
return size;
}
int addRecord(struct creditCard *card3)
{
count = count++;
fprintf(stderr, "count is %d \n", count);
int p;
struct creditCard *tempStruct;
//struct creditCard *dummy;
char fName, lName, month, number;
//tempStruct = (struct creditCard *) malloc (count * sizeof(struct creditCard)); //allocate memory to a dummy record
tempStruct = (struct creditCard *) malloc ((count+1) * sizeof(struct creditCard)); //allocate memory to a dummy record
//dummy = (struct creditCard *) malloc (sizeof(struct creditCard));
//dummy = (struct creditCard *) malloc (2 * sizeof(struct creditCard));
card3 = headPtr; //start at the beginning of the old database
for (p = 1; p < count; p++) //copies the old database in the new database up to the record before the newly allocated record
{
memcpy(tempStruct->firstName, card3->firstName, 100);
memcpy(tempStruct->lastName, card3->lastName, 100);
memcpy(tempStruct->cardNumber, card3->cardNumber, 17);
memcpy(tempStruct->expMonth, card3->expMonth, 10);
fprintf(stderr, "first name is %s\n", tempStruct->firstName);
if (p == count-1)
{
tempStruct++;
}
else
{
tempStruct++;
card3++;
}
}
printf("Please enter your first name.\n");
scanf("%s", &fName);
fprintf(stderr, "fname is %s\n", &fName);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->firstName, &fName,100);//put first name in struct
fprintf(stderr, "struct name is %s\n", tempStruct->firstName);
//fprintf(stderr, "dummy name is %s\n", dummy->firstName);
printf("Please enter your last name.\n");
scanf("%s", &lName);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->lastName,&lName,100);//put last name in struct
printf("Please enter your 16 digit credit card number with no spaces.\n");
scanf("%s", &number);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->cardNumber,&number,17);//put creditcard number in struct
printf("Please enter the month in which your credit card expires.\n");
scanf("%s", &month);
memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
//memcpy(dummy->expMonth,&month, 10); //put month of expiration in struct
//code below copies stuff from the dummy record to the new database called tempStruct
//memcpy(tempStruct->firstName, dummy->firstName, 100);
//memcpy(tempStruct->lastName, dummy->lastName, 100);
//memcpy(tempStruct->cardNumber, dummy->cardNumber, 17);
//memcpy(tempStruct->expMonth, dummy->expMonth, 10);
card3 = tempStruct; //put the new database in place of the old database
//free(dummy); //clear memory for the dummy record because we don't need it anymore
return 0;
}
int deleteRecord(struct creditCard *card4) //goes to the last record in the database and clears the memory for it, essentially deleting it
{
count = count--;
int l;
struct creditCard *newDb; //will hold the new database with one less record at the end
newDb = (struct creditCard *) malloc(count * sizeof(struct creditCard));
for (l = 0; l < 4; l++)
{
memcpy(newDb->firstName,card4->firstName,100);
memcpy(newDb->lastName,card4->lastName,100);
memcpy(newDb->cardNumber,card4->cardNumber,17);
memcpy(newDb->expMonth,card4->expMonth,10);
card4++;
}
//now we need to put the data into the new record
card4 = newDb; //put the new database into ptr to hold as the new database
return 0;
}
int printCreditCard(struct creditCard *card)
{
card = headPtr; //start at the beginning of the database
int i;
if (count == 0)
{
printf("The database is empty\n");
return 0;
}
else
{
for (i = 1; i <= count; i++)
{
printf("Credit Card Record %d\n", i);
fprintf(stderr, "First Name = \%s\n", card-> firstName);
fprintf(stderr, "Last Name = \%s\n", card-> lastName);
fprintf(stderr, "Card Number = \%s\n", card-> cardNumber);
fprintf(stderr, "Expiration Date = \%s\n\n", card-> expMonth);
card++; //go to the next record to print
}
}
return 1; //we have now printed all records, go to main menu.
}
There is really a lot wrong here-- you should try using lint or another static analysis tool to help you find errors.
One particular problem -- when you input fname, you are passing scanf a pointer to a single character-- you really want to pass it a pointer to an array of characters (actually, you don't want to use scanf at all, but I won't get into that). Scanf is merrily copying the input characters into the memory positions after that single char, which of course will cause a segfault at some point.
You'll also need to learn to use some sort of debugger (gdb?) which will help you look at the core dump when you get a segfault so you can find where things went wrong.

Seg. Fault in Hash Table ADT - C

Edit:
Hash.c is updated with revisions from the comments, I am still getting a Seg fault. I must be missing something here that you guys are saying
I have created a hash table ADT using C but I am encountering a segmentation fault when I try to call a function (find_hash) in the ADT.
I have posted all 3 files that I created parse.c, hash.c, and hash.h, so you can see all of the variables. We are reading from the file gettysburg.txt which is also attached
The seg fault is occuring in parse.c when I call find_hash. I cannot figure out for the life of me what is going on here. If you need anymore information I can surely provide it.
sorry for the long amount of code I have just been completely stumped for a week now on this. Thanks in advance
The way I run the program is first:
gcc -o parse parse.c hash.c
then: cat gettysburg.txt | parse
Parse.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "hash.h"
#define WORD_SIZE 40
#define DICTIONARY_SIZE 1000
#define TRUE 1
#define FALSE 0
void lower_case_word(char *);
void dump_dictionary(Phash_table );
/*Hash and compare functions*/
int hash_func(char *);
int cmp_func(void *, void *);
typedef struct user_data_ {
char word[WORD_SIZE];
int freq_counter;
} user_data, *Puser_data;
int main(void)
{
char c, word1[WORD_SIZE];
int char_index = 0, dictionary_size = 0, num_words = 0, i;
int total=0, largest=0;
float average = 0.0;
Phash_table t; //Pointer to main hash_table
int (*Phash_func)(char *)=NULL; //Function Pointers
int (*Pcmp_func)(void *, void *)=NULL;
Puser_data data_node; //pointer to hash table above
user_data * find;
printf("Parsing input ...\n");
Phash_func = hash_func; //Assigning Function pointers
Pcmp_func = cmp_func;
t = new_hash(1000,Phash_func,Pcmp_func);
// Read in characters until end is reached
while ((c = getchar()) != EOF) {
if ((c == ' ') || (c == ',') || (c == '.') || (c == '!') || (c == '"') ||
(c == ':') || (c == '\n')) {
// End of a word
if (char_index) {
// Word is not empty
word1[char_index] = '\0';
lower_case_word(word1);
data_node = (Puser_data)malloc(sizeof(user_data));
strcpy(data_node->word,word1);
printf("%s\n", data_node->word);
//!!!!!!SEG FAULT HERE!!!!!!
if (!((user_data *)find_hash(t, data_node->word))){ //SEG FAULT!!!!
insert_hash(t,word1,(void *)data_node);
}
char_index = 0;
num_words++;
}
} else {
// Continue assembling word
word1[char_index++] = c;
}
}
printf("There were %d words; %d unique words.\n", num_words,
dictionary_size);
dump_dictionary(t); //???
}
void lower_case_word(char *w){
int i = 0;
while (w[i] != '\0') {
w[i] = tolower(w[i]);
i++;
}
}
void dump_dictionary(Phash_table t){ //???
int i;
user_data *cur, *cur2;
stat_hash(t, &(t->total), &(t->largest), &(t->average)); //Call to stat hash
printf("Number of unique words: %d\n", t->total);
printf("Largest Bucket: %d\n", t->largest);
printf("Average Bucket: %f\n", t->average);
cur = start_hash_walk(t);
printf("%s: %d\n", cur->word, cur->freq_counter);
for (i = 0; i < t->total; i++)
cur2 = next_hash_walk(t);
printf("%s: %d\n", cur2->word, cur2->freq_counter);
}
int hash_func(char *string){
int i, sum=0, temp, index;
for(i=0; i < strlen(string);i++){
sum += (int)string[i];
}
index = sum % 1000;
return (index);
}
/*array1 and array2 point to the user defined data struct defined above*/
int cmp_func(void *array1, void *array2){
user_data *cur1= array1;
user_data *cur2= array2;//(user_data *)array2;
if(cur1->freq_counter < cur2->freq_counter){
return(-1);}
else{ if(cur1->freq_counter > cur2->freq_counter){
return(1);}
else return(0);}
}
hash.c
#include "hash.h"
Phash_table new_hash (int size, int(*hash_func)(char*), int(*cmp_func)(void*, void*)){
int i;
Phash_table t;
t = (Phash_table)malloc(sizeof(hash_table)); //creates the main hash table
t->buckets = (hash_entry **)malloc(sizeof(hash_entry *)*size); //creates the hash table of "size" buckets
t->size = size; //Holds the number of buckets
t->hash_func = hash_func; //assigning the pointer to the function in the user's program
t->cmp_func = cmp_func; // " "
t->total=0;
t->largest=0;
t->average=0;
t->sorted_array = NULL;
t->index=0;
t->sort_num=0;
for(i=0;i<size;i++){ //Sets all buckets in hash table to NULL
t->buckets[i] = NULL;}
return(t);
}
void free_hash(Phash_table table){
int i;
hash_entry *cur;
for(i = 0; i<(table->size);i++){
if(table->buckets[i] != NULL){
for(cur=table->buckets[i]; cur->next != NULL; cur=cur->next){
free(cur->key); //Freeing memory for key and data
free(cur->data);
}
free(table->buckets[i]); //free the whole bucket
}}
free(table->sorted_array);
free(table);
}
void insert_hash(Phash_table table, char *key, void *data){
Phash_entry new_node; //pointer to a new node of type hash_entry
int index;
new_node = (Phash_entry)malloc(sizeof(hash_entry));
new_node->key = (char *)malloc(sizeof(char)*(strlen(key)+1)); //creates the key array based on the length of the string-based key
new_node->data = data; //stores the user's data into the node
strcpy(new_node->key,key); //copies the key into the node
//calling the hash function in the user's program
index = table->hash_func(key); //index will hold the hash table value for where the new node will be placed
table->buckets[index] = new_node; //Assigns the pointer at the index value to the new node
table->total++; //increment the total (total # of buckets)
}
void *find_hash(Phash_table table, char *key){
int i;
hash_entry *cur;
printf("Inside find_hash\n"); //REMOVE
for(i = 0;i<table->size;i++){
if(table->buckets[i]!=NULL){
for(cur = table->buckets[i]; cur->next != NULL; cur = cur->next){
if(strcmp(table->buckets[i]->key, key) == 0)
return((table->buckets[i]->data));} //returns the data to the user if the key values match
} //otherwise return NULL, if no match was found.
}
return NULL;
}
void stat_hash(Phash_table table, int *total, int *largest, float *average){
int node_num[table->size]; //creates an array, same size as table->size(# of buckets)
int i,j, count = 0;
int largest_buck = 0;
hash_entry *cur;
for(i = 0; i < table->size; i ++){
if(table->buckets[i] != NULL){
for(cur=table->buckets[i]; cur->next!=NULL; cur = cur->next){
count ++;}
node_num[i] = count;
count = 0;}
}
for(j = 0; j < table->size; j ++){
if(node_num[j] > largest_buck)
largest_buck = node_num[j];}
*total = table->total;
*largest = largest_buck;
*average = (table->total) / (table->size);
}
void *start_hash_walk(Phash_table table){
Phash_table temp = table;
int i, j, k;
hash_entry *cur; //CHANGE IF NEEDED to HASH_TABLE *
if(table->sorted_array != NULL) free(table->sorted_array);
table->sorted_array = (void**)malloc(sizeof(void*)*(table->total));
for(i = 0; i < table->total; i++){
if(table->buckets[i]!=NULL){
for(cur=table->buckets[i]; cur->next != NULL; cur=cur->next){
table->sorted_array[i] = table->buckets[i]->data;
}}
}
for(j = (table->total) - 1; j > 0; j --) {
for(k = 1; k <= j; k ++){
if(table->cmp_func(table->sorted_array[k-1], table->sorted_array[k]) == 1){
temp -> buckets[0]-> data = table->sorted_array[k-1];
table->sorted_array[k-1] = table->sorted_array[k];
table->sorted_array[k] = temp->buckets[0] -> data;
}
}
}
return table->sorted_array[table->sort_num];
}
void *next_hash_walk(Phash_table table){
table->sort_num ++;
return table->sorted_array[table->sort_num];
}
hash.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct hash_entry_ { //Linked List
void *data; //Generic pointer
char *key; //String-based key value
struct hash_entry_ *next; //Self-Referencing pointer
} hash_entry, *Phash_entry;
typedef struct hash_table_ {
hash_entry **buckets; //Pointer to a pointer to a Linked List of type hash_entry
int (*hash_func)(char *);
int (*cmp_func)(void *, void *);
int size;
void **sorted_array; //Array used to sort each hash entry
int index;
int total;
int largest;
float average;
int sort_num;
} hash_table, *Phash_table;
Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *, void *));
void free_hash(Phash_table table);
void insert_hash(Phash_table table, char *key, void *data);
void *find_hash(Phash_table table, char *key);
void stat_hash(Phash_table table, int *total, int *largest, float *average);
void *start_hash_walk(Phash_table table);
void *next_hash_walk(Phash_table table);
Gettysburg.txt
Four score and seven years ago, our fathers brought forth upon this continent a new nation: conceived in liberty, and dedicated to the proposition that all men are created equal.
Now we are engaged in a great civil war. . .testing whether that nation, or any nation so conceived and so dedicated. . . can long endure. We are met on a great battlefield of that war.
We have come to dedicate a portion of that field as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.
But, in a larger sense, we cannot dedicate. . .we cannot consecrate. . . we cannot hallow this ground. The brave men, living and dead, who struggled here have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember, what we say here, but it can never forget what they did here.
It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us. . .that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion. . . that we here highly resolve that these dead shall not have died in vain. . . that this nation, under God, shall have a new birth of freedom. . . and that government of the people. . .by the people. . .for the people. . . shall not perish from the earth.
It's possible that one of several problems with this code are loops like:
for(table->buckets[i];
table->buckets[i]->next != NULL;
table->buckets[i] = table->buckets[i]->next)
...
The initializing part of the for loop (table->buckets[i]) has no effect. If i is 0 and table->buckets[0] == NULL, then the condition on this loop (table->buckets[i]->next != NULL) will dereference a null pointer and crash.
That's where your code seemed to be crashing for on my box, at least. When I changed several of your loops to:
if (table->buckets[i] != NULL) {
for(;
table->buckets[i]->next != NULL;
table->buckets[i] = table->buckets[i]->next)
...
}
...it kept crashing, but in a different place. Maybe that will help get you unstuck?
Edit: another potential problem is that those for loops are destructive. When you call find_hash, do you really want all of those buckets to be modified?
I'd suggest using something like:
hash_entry *cur;
// ...
if (table->buckets[i] != NULL) {
for (cur = table->buckets[i]; cur->next != NULL; cur = cur->next) {
// ...
}
}
When I do that and comment out your dump_dictionary function, your code runs without crashing.
Hmm,
here's hash.c
#include "hash.h"
Phash_table new_hash (int size, int(*hash_func)(char*), int(*cmp_func)(void*, void*)){
int i;
Phash_table t;
t = (Phash_table)calloc(1, sizeof(hash_table)); //creates the main hash table
t->buckets = (hash_entry **)calloc(size, sizeof(hash_entry *)); //creates the hash table of "size" buckets
t->size = size; //Holds the number of buckets
t->hash_func = hash_func; //assigning the pointer to the function in the user's program
t->cmp_func = cmp_func; // " "
t->total=0;
t->largest=0;
t->average=0;
for(i=0;t->buckets[i] != NULL;i++){ //Sets all buckets in hash table to NULL
t->buckets[i] = NULL;}
return(t);
}
void free_hash(Phash_table table){
int i;
for(i = 0; i<(table->size);i++){
if(table->buckets[i]!=NULL)
for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
free(table->buckets[i]->key); //Freeing memory for key and data
free(table->buckets[i]->data);
}
free(table->buckets[i]); //free the whole bucket
}
free(table->sorted_array);
free(table);
}
void insert_hash(Phash_table table, char *key, void *data){
Phash_entry new_node; //pointer to a new node of type hash_entry
int index;
new_node = (Phash_entry)calloc(1,sizeof(hash_entry));
new_node->key = (char *)malloc(sizeof(char)*(strlen(key)+1)); //creates the key array based on the length of the string-based key
new_node->data = data; //stores the user's data into the node
strcpy(new_node->key,key); //copies the key into the node
//calling the hash function in the user's program
index = table->hash_func(key); //index will hold the hash table value for where the new node will be placed
table->buckets[index] = new_node; //Assigns the pointer at the index value to the new node
table->total++; //increment the total (total # of buckets)
}
void *find_hash(Phash_table table, char *key){
int i;
hash_entry *cur;
printf("Inside find_hash\n"); //REMOVE
for(i = 0;i<table->size;i++){
if(table->buckets[i]!=NULL){
for (cur = table->buckets[i]; cur != NULL; cur = cur->next){
//for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
if(strcmp(cur->key, key) == 0)
return((cur->data));} //returns the data to the user if the key values match
} //otherwise return NULL, if no match was found.
}
return NULL;
}
void stat_hash(Phash_table table, int *total, int *largest, float *average){
int node_num[table->size];
int i,j, count = 0;
int largest_buck = 0;
hash_entry *cur;
for(i = 0; i < table->size; i ++)
{
if(table->buckets[i]!=NULL)
for (cur = table->buckets[i]; cur != NULL; cur = cur->next){
//for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
count ++;}
node_num[i] = count;
count = 0;
}
for(j = 0; j < table->size; j ++){
if(node_num[j] > largest_buck)
largest_buck = node_num[j];}
*total = table->total;
*largest = largest_buck;
*average = (table->total) /(float) (table->size); //oook: i think you want a fp average
}
void *start_hash_walk(Phash_table table){
void* temp = 0; //oook: this was another way of overwriting your input table
int i, j, k;
int l=0; //oook: new counter for elements in your sorted_array
hash_entry *cur;
if(table->sorted_array !=NULL) free(table->sorted_array);
table->sorted_array = (void**)calloc((table->total), sizeof(void*));
for(i = 0; i < table->size; i ++){
//for(i = 0; i < table->total; i++){ //oook: i don't think you meant total ;)
if(table->buckets[i]!=NULL)
for (cur = table->buckets[i]; cur != NULL; cur = cur->next){
//for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
table->sorted_array[l++] = cur->data;
}
}
//oook: sanity check/assert on expected values
if (l != table->total)
{
printf("oook: l[%d] != table->total[%d]\n",l,table->total);
}
for(j = (l) - 1; j > 0; j --) {
for(k = 1; k <= j; k ++){
if (table->sorted_array[k-1] && table->sorted_array[k])
{
if(table->cmp_func(table->sorted_array[k-1], table->sorted_array[k]) == 1){
temp = table->sorted_array[k-1]; //ook. changed temp to void* see assignment
table->sorted_array[k-1] = table->sorted_array[k];
table->sorted_array[k] = temp;
}
}
else
printf("if (table->sorted_array[k-1] && table->sorted_array[k])\n");
}
}
return table->sorted_array[table->sort_num];
}
void *next_hash_walk(Phash_table table){
/*oook: this was blowing up since you were incrementing past the size of sorted_array..
NB: *you **need** to implement some bounds checking here or you will endup with more seg-faults!!*/
//table->sort_num++
return table->sorted_array[table->sort_num++];
}
here's parse.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h> //oook: added so you can assert ;)
#include "hash.h"
#define WORD_SIZE 40
#define DICTIONARY_SIZE 1000
#define TRUE 1
#define FALSE 0
void lower_case_word(char *);
void dump_dictionary(Phash_table );
/*Hash and compare functions*/
int hash_func(char *);
int cmp_func(void *, void *);
typedef struct user_data_ {
char word[WORD_SIZE];
int freq_counter;
} user_data, *Puser_data;
int main(void)
{
char c, word1[WORD_SIZE];
int char_index = 0, dictionary_size = 0, num_words = 0, i;
int total=0, largest=0;
float average = 0.0;
Phash_table t; //Pointer to main hash_table
int (*Phash_func)(char *)=NULL; //Function Pointers
int (*Pcmp_func)(void *, void *)=NULL;
Puser_data data_node; //pointer to hash table above
user_data * find;
printf("Parsing input ...\n");
Phash_func = hash_func; //Assigning Function pointers
Pcmp_func = cmp_func;
t = new_hash(1000,Phash_func,Pcmp_func);
// Read in characters until end is reached
while ((c = getchar()) != EOF) {
if ((c == ' ') || (c == ',') || (c == '.') || (c == '!') || (c == '"') ||
(c == ':') || (c == '\n')) {
// End of a word
if (char_index) {
// Word is not empty
word1[char_index] = '\0';
lower_case_word(word1);
data_node = (Puser_data)calloc(1,sizeof(user_data));
strcpy(data_node->word,word1);
printf("%s\n", data_node->word);
//!!!!!!SEG FAULT HERE!!!!!!
if (!((user_data *)find_hash(t, data_node->word))){ //SEG FAULT!!!!
dictionary_size++;
insert_hash(t,word1,(void *)data_node);
}
char_index = 0;
num_words++;
}
} else {
// Continue assembling word
word1[char_index++] = c;
}
}
printf("There were %d words; %d unique words.\n", num_words,
dictionary_size);
dump_dictionary(t); //???
}
void lower_case_word(char *w){
int i = 0;
while (w[i] != '\0') {
w[i] = tolower(w[i]);
i++;
}
}
void dump_dictionary(Phash_table t){ //???
int i;
user_data *cur, *cur2;
stat_hash(t, &(t->total), &(t->largest), &(t->average)); //Call to stat hash
printf("Number of unique words: %d\n", t->total);
printf("Largest Bucket: %d\n", t->largest);
printf("Average Bucket: %f\n", t->average);
cur = start_hash_walk(t);
if (!cur) //ook: do test or assert for null values
{
printf("oook: null== (cur = start_hash_walk)\n");
exit(-1);
}
printf("%s: %d\n", cur->word, cur->freq_counter);
for (i = 0; i < t->total; i++)
{//oook: i think you needed these braces
cur2 = next_hash_walk(t);
if (!cur2) //ook: do test or assert for null values
{
printf("oook: null== (cur2 = next_hash_walk(t) at i[%d])\n",i);
}
else
printf("%s: %d\n", cur2->word, cur2->freq_counter);
}//oook: i think you needed these braces
}
int hash_func(char *string){
int i, sum=0, temp, index;
for(i=0; i < strlen(string);i++){
sum += (int)string[i];
}
index = sum % 1000;
return (index);
}
/*array1 and array2 point to the user defined data struct defined above*/
int cmp_func(void *array1, void *array2){
user_data *cur1= array1;
user_data *cur2= array2;//(user_data *)array2;
/* ooook: do assert on programmatic errors.
this function *requires non-null inputs. */
assert(cur1 && cur2);
if(cur1->freq_counter < cur2->freq_counter){
return(-1);}
else{ if(cur1->freq_counter > cur2->freq_counter){
return(1);}
else return(0);}
}
follow the //ooks
Explanation:
There were one or two places this was going to blow up in.
The quick fix and answer to your question was in parse.c, circa L100:
cur = start_hash_walk(t);
printf("%s: %d\n", cur->word, cur->freq_counter);
..checking that cur is not null before calling printf fixes your immediate seg-fault.
But why would cur be null ? ~because of this bad-boy:
void *start_hash_walk(Phash_table table)
Your hash_func(char *string) can (& does) return non-unique values. This is of course ok except that you have not yet implemented your linked list chains. Hence you end up with table->sorted_array containing less than table->total elements ~or you would if you were iterating over all table->size buckets ;)
There are one or two other issues.
For now i hacked Nate Kohl's for(cur=table->buckets[i]; cur->next != NULL; cur=cur->next) further, to be for(cur=table->buckets[i]; cur != NULL; cur=cur->next) since you have no chains. But this is *your TODO so enough said about that.
Finally. note that in next_hash_walk(Phash_table table) you have:
table->sort_num++
return table->sorted_array[table->sort_num];
Ouch! Do check those array bounds!
Notes
1) If you're function isn't designed to change input, then make the input const. That way the compiler may well tell you when you're inadvertently trashing something.
2) Do bound checking on your array indices.
3) Do test/assert for Null pointers before attempting to use them.
4) Do unit test each of your functions; never write too much code before compiling & testing.
5) Use minimal test-data; craft it such that it limit-tests your code & attempts to break it in cunning ways.
6) Do initialise you data structures!
7)Never use egyptian braces ! {
only joking ;)
}
PS Good job so far ~> pointers are tricky little things! & a well asked question with all the necessary details so +1 and gl ;)
(//oook: maybe add a homework tag)

Resources