Segmentation Fault after few realloc | Array of Structs - c

Well, I'm implementing a hash table with array of struct form, like this:
int SIZE = 769;
int entries=0;
typedef struct entry {
long id;
long n_article;
long id_rev;
long uni_rev;
} Entry;
typedef Entry * THash;
THash init_THash ()
{
int i;
THash t = (THash) malloc(SIZE*sizeof(struct entry));
//...
return t;
}
I have a function that add something to the hash table and if the entries is more than 70% of the SIZE, I resize the table.
THash resize_THash (THash h){
int i;
int prime = SIZE*2;
h = (THash) realloc (h,(prime)*sizeof(struct entry));
//...
SIZE = prime;
return h;
}
void add_THash (THash h,long id, long idrevision){
int i,r=0;
if (entries > SIZE * 0.7) h=resize_THash(h);
//...
entries++;
}
The init of the hash table is correct, but the problem is when I realloc/resize 3 times, stops working, giving me segmentation fault; At this point I tried everything and I failed. Anyone can explain me, why this implementation is wrong?
For example: in this main, if the condition is i<3000 it works, but if it's i<6000, doesnt work.
int main()
{
int i;
THash t = init_THash();
for(int i=10;i<3000;i++){
add_THash(t,i,627604899);
}
printf("SIZE:%d\n",SIZE);
printf("ENTRIES: %d\n",entries);
return 0;
}

The add_Thash function doesn't return the new pointer, leaving the caller to use the old, now invalid, one.

Related

Leetcode Segmentation fault trying to reset hashtable data structure between calls (partially solved)

I'm doing a problem on Leetcode. It says I passed my first test case but I failed my second with a simple wrong answer. When I ran that case manually, I passed, so I know it's something to do with data persistence between their runs. It's obviously the hash table I'm using, which I first declared globally. To fix, I first tried resetting to zero with calloc and memset but I got segfault errors.
I decided the logical thing is to create the hash inside the caller function, so each time it's called it would be reinitalized. However, I am still getting seg fault errors (address sanitizer deadly signal) even though it seems like it should work. Am I misusing pointers?
Here is my code that's not working. The comments //\ represent lines of code I had before, where it did work case by case. There were not many changes- mostly to return the hash. I comment where the seg fault occurs (per my printf debugging). I hope I didn't miss anything. I'm trying to display two coding instanecs in one because it's mostly reduntant.
#define SIZE 1000
typedef struct htent{
struct htent* next;
int key, value;
} htent;
int hashf(int val, int size){
return val % SIZE; // don't need anything fancy
}
htent* create_new_htent(int val){ // the value is its own key
htent* ent = malloc(sizeof(htent));
ent->next = NULL;
ent->key = val;
ent->value = val;
return ent;
}
// htent* ht[SIZE] = {0}; //\\ This was my method before (main difference)
htent* build_hash_table_n_get_lowest(int* nums, int numsSize, int* low){ //\\ returned void before
htent* ht[SIZE] = {0}; //\\ before was commented out
int hash;
int running_low = 10000; // large #
htent* tmp;
for (int i = 0; i < numsSize; i++){
if (nums[i] < 1 ) continue; // drop negatives
if (nums[i] < running_low) running_low = nums[i];
printf("%d: Running Low %d\n", i, running_low);
htent* ent = create_new_htent(nums[i]);
hash = hashf(nums[i], numsSize);
if (ht[hash] == NULL){
ht[hash] = ent; // singly linked list
continue;
}
tmp = ht[hash];
while(tmp->next != NULL){
tmp = tmp->next;
}
tmp->next = ent;
}
*low = running_low;
return ht; //\\ was commented out before
}
int find_missing_lowest(htent** ht, int numsSize, int lowest){
int moving_target = 1;
for (int i = 0; i<numsSize; i++){
if (ht[moving_target] == NULL){ // SEG FAULTS HERE!!!
return moving_target;
}
moving_target++;
}
return moving_target;
}
int firstMissingPositive(int* nums, int numsSize){ // Function Leetcode calls
int lowest;
htent* ht = build_hash_table_n_get_lowest(nums, numsSize, &lowest); // tried with htent**
return find_missing_lowest(ht, numsSize, lowest);
}
EDIT: I built this function using the global scope approach and it works and these tests pass (just have to handle edge cases), but there has to be a better way;
void refresh_hashtable(){
for (int i = 0; i<SIZE; i++){
ht[i] = NULL;
}
}

My function is returning segmentation fault error for aparently nothing wrong

I'm making an hashing table data structure and having segmentation fault error on my inicialization function. Here the code:
void allocTableSlots(alu **table, int index){
if(index == MAX)
return;
else{
table[index] = calloc(1, sizeof(alu));
table[index]->registration = -1;
table[index]->next = -1;
allocTableSlots(table, index+1);
}
}
void initializateHashTable(hash *hashing){
hashing = calloc(1, sizeof(hash));
allocTableSlots(hashing->table, 0);
hashing->collisionArea = 690;
}
My structs are these:
#define MAX 997
typedef struct alu{
int registration;
char name[80];
char email[80];
int next;
} alu;
typedef struct reg{
alu *table[MAX];
int collisionArea;
}hash;
The error comes in:
if(index == MAX)
on allocTableSlots() function
If I change MAX, for MAX-1, or any other number, like 500 the error still comes after position 499, so its not look like that I trying to access an invalid position of my array table
I already tried an iterative version (in case that my recursion has some error) but still the same
As suggested in the comments, you most likely should just return the pointer to the allocated block from the init function. Furthermore, if the maximum bucket size is known, as is in your code with MAX, the code simplifies to:
...
typedef struct reg {
alu table[MAX];
int collisionArea;
} hash;
hash *initializateHashTable(void) {
hash *t = calloc(1, sizeof *t);
if (!t) return NULL; // check calloc, just in case.
/* Whatever initialization you want to perform. As per your code,
setting registration and next members to -1 */
for (int i = 0; i < MAX; i++) {
t->table[i].registration = t->table[i].next = -1;
}
t->collisionArea = 690; // EDIT: Forgot the collisionArea
return t;
}

Insert function of Hashtable in C

So, I have the functions. How can I insert numbers in the Hashtable? A for that goes until the size of the table? I don't know what goes inside the for, if it is exists.
#include <stdio.h>
//Structure
typedef struct Element {
int key;
int value;
} Element;
typedef struct HashTable {
Element *table[11];
} HashTable;
//Create an empty Hash
HashTable* createHashTable() {
HashTable *Raking = malloc(sizeof(HashTable));
int i;
for (i = 0; i < 11; i++) {
Raking->table[i] = NULL;
}
return Raking;
}
//Insert element
void insertElement(HashTable *Raking, int key, int value) {
int h = hashFunction(key);
while(Raking->table[h] != NULL) {
if(Raking->table[h]->key == key) {
Raking->table[h]->value = value;
break;
}
h = (h + 1) % 11;
}
if(Raking->table[h] == NULL) {
Element *newElement = (Element*) malloc(sizeof(Element));
newElement->key = key;
newElement->value = value;
Raking->table[h] = newElement;
}
}
int main() {
HashTable * Ranking = createHashTable();
/** ??? **/
}
Could someone explain to me how to write my main function with these structures? In this case I'm fixing the number of elements in this table, right? (table [11]) What could I do for the user to determine the size of the hash table? is it possible? Or should I set the size?
I've added comments and changes to your code that I feel will be of use to you. I've also adapted it so that size is not hardcoded. Finally I free all the malloc-ed statements.
This compiles without errors and I've tested it for memory leaks and other errors using valgrind and found no complaints.
Let me know if something is not clear and the comments fail to explain it. I've tried to stick to your code as much as possible but I've not had a chance to test the functionality properly.
#include <stdio.h>
#include <stdlib.h>
//Structure
typedef struct Element {
int key;
int value;
} Element; /* you had a syntax error here */
typedef struct HashTable {
int size; /* we will need the size for the traversal */
Element *table; /* leave it as a pointer */
} HashTable; /* a syntax error here too */
HashTable* createHashTable(int size) {
HashTable *Ranking = malloc(sizeof(HashTable));
/* set the pointer to point to a dynamic array of size 'size' */
/* this way you don't have to hardcode the size */
Ranking->table = malloc(sizeof(Element) * size);
Ranking->size = size;
/* initialisation is a bit different because we don't have pointers here */
/* only table is a pointer, not its elements */
int i;
for (i = 0; i < size; i++) {
Ranking->table[i].key = 0;
Ranking->table[i].value = 0;
}
return Ranking;
}
/* I implemented a fake hashFunction just to test the code */
/* all it does is make sure the key does not exceed the size of the table */
int hashFunction(int key, int size)
{
return (key % size);
}
//Insert element
void insertElement(HashTable *Ranking, int key, int value) {
int h = hashFunction(key, Ranking->size);
int i = 0;
/* if hash is full and key doesn't exist your previous loop would have gone on forever, I've added a check */
/* also notice that I check if table[h] has empty key, not if it's null as this is not a pointer */
while(Ranking->table[h].key != 0 && (i < Ranking->size)) {
if(Ranking->table[h].key == key) {
Ranking->table[h].value = value;
return; /* break is intended to quit the loop, but actually we want to exit the function altogether */
}
h = (h + 1) % Ranking->size; /* changed 11 to the size specified */
i++; /* advance the loop index */
}
/* okay found a free slot, store it there */
if(Ranking->table[h].key == 0) {
/* we now do direct assignment, no need for pointers */
Ranking->table[h].key = key;
Ranking->table[h].value = value;
}
}
int main() {
int size = 0;
scanf(" %d", &size);
HashTable *Ranking = createHashTable(size);
insertElement(Ranking, 113, 10); /* this is just a test, 113 will be hashed to be less than size */
/* we free everything we have malloc'ed */
free(Ranking->table);
free(Ranking);
return 0;
}

C - Passing a Pointer to a Function and then Passing that Same Pointer Inside the Function to Another Function

Whew! Long title...here's some pseudo-code to explain that verbiage:
int main(){
int* ptr = function1(); //the data that ptr points to is correct here
function2(ptr);
}
int function2(int* ptr){
//the data that ptr points to is still correct
int i;
for(i=0;i<length;printf("%d\n", (*ptr)[i]), i++); //since ptr points to a contiguous block of memory
function3(ptr);
}
int function3(int* ptr){
//the data that ptr points to is INCORRECT!!!
}
Why would the data in function3 be incorrect?
Note: function1 performs a malloc() and returns the pointer to that memory.
ACTUAL CODE
#include <stdlib.h>
#include <stdio.h>
//Structures
struct hash_table_data_
{
int key, data;
struct hash_table_data_ *next, *prev;
};
struct hash_table_
{
int num_entries;
struct hash_table_data_ **entries;
};
typedef struct hash_table_data_ hash_table_data;
typedef struct hash_table_ hash_table;
//Prototypes
hash_table *new_hash_table(int num_entries);
int hash_table_add(hash_table *ht, int key, int data);
int hash_table_loader(hash_table* ht);
//Main
int main()
{
int num_entries = 8;//THIS MUST BE AUTOMATED
hash_table* ht = new_hash_table(num_entries);
hash_table_loader(ht);
return 0;
}
//Function Definitions
hash_table *new_hash_table(int num_entries)
{
hash_table* ht = (hash_table*) malloc(sizeof(hash_table));
hash_table_data* array = malloc(num_entries * sizeof(hash_table_data));
int i;
for (i=0;i<num_entries;i++)
{
array[i].key = -1;
array[i].data = -1;
array[i].next = NULL;
array[i].prev = NULL;
}
ht->entries = &array;
ht->num_entries = num_entries;
return ht;
}
int hash_table_add(hash_table *ht, int key, int data)
{
//VERIFY THAT THE VALUE ISN'T ALREADY IN THE TABLE!!!!!!!!!!!
int num_entries = ht->num_entries;
hash_table_data* array = *(ht->entries); //array elements are the LL base
int hash_val = key%num_entries;
printf("adding an element now...\n");
printf("current key: %d\n", array[hash_val].key);
int i;
for(i=0;i<num_entries;printf("%d\n", (*(ht->entries))[i].key),i++);//DATA IS INCORRECT!!!!
if (array[hash_val].key == -1)//is this the base link?
{
printf("added a new base link!\n");
array[hash_val].key = key;
array[hash_val].data = data;
array[hash_val].next = NULL;
array[hash_val].prev = &(array[hash_val]);
}
else//since it's not the base link...do stuff
{
hash_table_data* new_link = malloc(sizeof(hash_table_data));
new_link->key = key;//set the key value
new_link->data = data;//set the data value
if (array[hash_val].next == NULL)//we must have the second link
{
printf("added a new second link!\n");
new_link->prev = &(array[hash_val]); //set the new link's previous to be the base link
array[hash_val].next = new_link; //set the first link's next
}
else//we have the 3rd or greater link
{
printf("added a new 3rd or greater link!\n");
hash_table_data next_link_val = *(array[hash_val].next);
while (next_link_val.next != NULL)//follow the links until we reach the last link
{
next_link_val = *(next_link_val.next);//follow the current link to the next
}
//now that we've reached the last link, link it to the new_link
next_link_val.next = new_link; //link the last link to the new link
new_link->prev = &(next_link_val); //link the new link to the last link
}
}
return 0;
}
int hash_table_loader(hash_table* ht)
{
int i;
for(i=0;i<(ht->num_entries);printf("%d\n", (*(ht->entries))[i].key),i++); //DATA IS STILL CORRECT HERE
FILE *infile;
infile = fopen("input.txt", "r");
while(!feof(infile))
{
int key,data;
fscanf(infile, "%d %d", &key, &data);
hash_table_add(ht, key, data);
}
fclose(infile);
}
Note: Issue occurring the first time hash_table_add() is called.
Your first problem is here:
ht->entries = &array;
You cause the structure to hold a hash_table_data** which points to the variable hash_table_data* array which is local to the function; then you exit the function and return a pointer to the structure. The structure still exists (it was allocated via malloc(), and the stuff that array points to still exists, but array itself does not. Accordingly, this pointer within the structure is now invalid.
As far as I can tell, there is no reason for you to be holding a pointer-to-pointer here. Just use hash_table_data* as the entries type, and copy array into that struct member. Pointers are values too.
I guess you iterate incorrectly
for(i=0;i<length;printf("%d\n", (*ptr)[i]), i++);
this is nonsense.
You should rewrite it as this:
for(i=0;i<length;i++)
printf("%d\n", ptr[i]);
(*ptr)[i] is just wrong, it doesn't make sense if you think about it.
*ptr is the first element of the pointed-to array of ints.
ptr[i] is thi ith one, this is what you need.
Please, read Section 6 carefully.
A couple of advises based on this question:
Don't write overcomplicated code like this for statement with comma operator used, it just rarely needed and leads not only to confusion, but to mistakes (although no mistakes with it in this particular example)
Look carefully for mistakes, don't blame everything on functions. If your code doesn't work, try finding the exact place which is wrong and prove it. In this example people who tested your code were right: functions are definitely not the cause of the error.
hash_table *new_hash_table(int num_entries)
{
hash_table* ht = (hash_table*) malloc(sizeof(hash_table));
hash_table_data* array = malloc(num_entries * sizeof(hash_table_data));
// ....
ht->entries = &array; // Problem
// ...
return ht;
} // Life time of array ends at this point.
You are taking the reference of the local variable array and assigning it to ht->entries which is no more valid once the function returns.

error in function returning structure

#include<stdio.h>
#include "amicablenumber.h"
int i,j;
struct amicable
{
int **amicablePair;
int size;
};
main()
{
int startnum = 250;
int endnum = 1000;
struct amicable* ami;
ami = getAmicablePairs(startnum, endnum);
printf("{");
for(int i = 0; i<ami->size; i++)
{
printf("{%d, %d}",ami->amicablePair[i][0], ami->amicablePair[i][1]);
}
printf("}");
}
amicable *getAmicablePairs(int startnum,int endnum)
{
int size=0;
int sumfactors(int);
amicable record;
for(i=startnum;i<=endnum;i++)
{
for(j=endnum;j>=startnum;j--)
{
if((sumfactors(i)==j)&&(sumfactors(j)==i) && (i!=j))
{
record.amicablePair[size][0]=i;
record.amicablePair[size][1]=j;
size++;
}}}
record.size=size;
return record;
}
int sumfactors(int number)
{
int sum=0;
for(i=1;i<number;i++)
{
if(number%i==0)
sum +=i;
}
return sum;
}
in the above code i m getting a error
cannot convert amicable to amicable* in return
getAmicablePairs is declared to return a pointer to an amicable:
amicable *getAmicablePairs(...)
but you then try to return an amicable:
return record;
rather than a pointer to one.
Note that one "obvious" fix, which is to return a pointer to record:
return &record;
won't work, because you'd be returning a pointer to a variable that was about to go away as soon as getAmicablePairs returns. Instead you need to create a record using malloc and return that; something like this:
amicable *record = (amicable*) malloc(sizeof(amicable));
You'll need to change all your record. into record->.
Note also that you're writing into the amicablePair member of your structure without allocating it - that's going to cause a crash. You need to malloc the amicablePair as well as the amicable.
You are returning an (amicable *) - a pointer to an amicable, but your function creates an (amicable) (not a pinter to one).
Instead of declaring
amicable record;
you need to do this (or an equivalent):
amicable *record = (amicable *) malloc(sizeof(amicable));
and then access via "record->" rather than "record."
Note: With the above approach you will need to free() the above allocation when you are finished with it.

Resources