C - pointer to struct to array of pointers - c

I have a linked list with a hash table in each node. The hash table is implemented by an array of pointers to structs. The whole management of this is made by a global static pointer to the linked list.
I changed a little bit the question! Now the question is more focused.
in the lookup and insert function to make the code shorter I assign
temp = cur_table->symbols_table[entry];
but I see that temp gets NULL all the time.
I can't understand why is that happens?
The code is below in 3 modules.
Thank you in ahead.
symbols.h file:
#include <stdlib.h>
#include <stdio.h>
#define TABLE_SIZE 26
typedef struct symbol_node
{
char* name;
int type;
int role;
struct symbol_node* next;
} symbol_node;
typedef struct table_node
{
struct symbol_node* symbols_table[TABLE_SIZE];
struct table_node* prev;
struct table_node* next;
} table_node;
static struct table_node* cur_table;
//functions declarations:
void init_table();
int hash_function(char* id);
symbol_node* lookup(char* id_name);
symbol_node* insert(char* id_name);
// debug
void printtable();
symbols.c
void init_table() // creates the first node
{
int i = 0;
cur_table = NULL;
cur_table = (table_node*)malloc(sizeof(table_node));
cur_table->prev = NULL;
cur_table->next = NULL;
for(i=0; i < TABLE_SIZE; i++)
{
cur_table->symbols_table[i] = NULL;
}
}
symbol_node* lookup(char* id_name) // returns null if the id name not found
{
symbol_node* result = NULL;
symbol_node* temp = NULL;
int entry = atoi(id_name);
temp = cur_table->symbols_table[entry];
while(temp != NULL)
{
if( strcmp( id_name, temp->name ) == 0 )
{
result = temp;
break;
}
else
temp = temp->next;
}
return result;
}
symbol_node* insert(char* id_name)
{
symbol_node* result = NULL;
symbol_node* temp = NULL;
int index = -1;
if(lookup(id_name)==NULL)
{
index = atoi(id_name);
temp = cur_table->symbols_table[index];
while(temp!=NULL)
{
temp = temp->next;
}
temp = (symbol_node*)malloc(sizeof(symbol_node));
temp->next = NULL;
temp->name = id_name;
// TODO: other params
result = temp;
}
return result;
}
void printtable()
{
int i=0;
for(i=0; i<TABLE_SIZE; i++)
{
if(cur_table->symbols_table[i]==NULL)
printf("NULL at index %d\n",i);
else
printf("There are something\n");
}
}
main.c
void main()
{
int i=0;
symbol_node* t = NULL;
symbol_node* tt = NULL;
init_table();
t = insert("markhit");
t = insert("mark");
tt = lookup("mark");
printtable();
_getch();
free(t);
free(tt);
free(cur_table);
}

avoid memory allocation [`malloc'] statically. try it
cur_table = new table_node;
for statically allocated memory, you can not set your value for memory reason. when you are inserting it is not reallocating your cur_table

Related

Is there any way to 'reserve' some memory for a struct to make sure other functions can't overwrite it?

For context, I'm a new programmer to C and I wanted to make a toy implementation of a dictionary/map from a 'Person' struct to an integer. I'm using separate chaining, so I have a hash table of linked list pointers.
So far, I've been able to add one value to the linked list just fine, but when I call the function to get the value for the Person key I'm using, the memory at one of my nodes seems to get overwritten.
More info if it's helpful, using a singly linked list with one sentinel node at the head and a tail reference.
New to StackOverflow, so I can't actually embed the image, but pictured on left is the HashTable at the beginning of the function call, when nothing has been changed. The relevant stuff is the expanded part of the Variables menu, which shows that at position 58 is a pointer to 0x61f8e0, the linked list. The linked list has a head pointer to 0x61f760, which is the sentinel value, and a tail pointer to 0x61f864, currently pointing to a Node with the value (3) for a Person named Robert who's 36 years old. The tail pointer's next field points to 0x0 (not pictured), like intended. The picture follows: https://i.stack.imgur.com/F9EJ9.png
This is what happens as soon as the first statement (which hashes the Person pointer very naively) is executed: https://i.stack.imgur.com/UJvGy.png. As you'll see, the value is now some random long number, the intrinsic age is now 1 instead of 36, the saved name is now gibberish, and worst of all the next pointer now points somewhere completely random (0x61fb10).
The function in question follows.
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
Here is the hash function, in case that's what's causing the problems.
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
And just because why not, here's all of the short amount of code I've written for this.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
typedef struct Node {
int val;
int savedAge;
char savedName[100];
struct Node* next;
} Node;
typedef struct {
int age;
char name[100];
} Person;
typedef struct {
Node* head;
Node* tail;
} List;
typedef struct {
List* table[100];
} HashTable;
int hash(Person*);
Person person(int age, char name[]) {
Person p;
p.age = age;
strcpy(p.name, name);
return p;
}
Node node(int val, Person p, Node* next) {
Node n;
n.val = val;
strcpy(n.savedName, p.name);
n.savedAge = p.age;
n.next = next;
return n;
}
List list() {
List l;
Node head = node(-1, person(0, "SENTINEL"), NULL);
l.head = &head;
l.tail = l.head;
return l;
}
void listAdd(List* l, Node n) {
Node* newTailPtr = &n;
l -> tail -> next = newTailPtr;
l -> tail = newTailPtr;
}
HashTable table() {
int table[100] = {0};
HashTable t;
memcpy(t.table, table, sizeof table);
return t;
}
HashTable tableAdd(HashTable t, Person key, int val) {
int num = hash(&key) % 100;
List* loc = t.table[num];
if ((int) loc == 0) {
List newList = list();
t.table[num] = &newList;
}
listAdd((List*) t.table[num], node(val, key, NULL));
return t;
}
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
int main() {
Person bob = person(36, "Robert");
printf(bob.name);
printf("\n");
HashTable tab = table();
tab = tableAdd(tab, bob, 3);
printf("Added Robert to table as 3\n");
int val = tableGet(tab, bob);
if (val == 3) {
printf("Success!\n");
} else {
printf("Failure, val is %d\n", val);
}
return 0;
}

Hashtable with linked list not work in c?

I've a problem with memory allocation for an hash table with linked list (for avoid collisions) in C.
I think that the problem is on allocation of an item.
I've made two scruct, one for the single item and one for the table.
The first have two pointer to next and prev item.
Please help me.
I stay on this code until 3 days.
The code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
unsigned long hash(char *str) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
return stringsum % CAPACITY;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table, CAPACITY);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
unsigned long index = hash(key);
printf("%u", index);
ht_item *_iterator; ht_item *prev;
for(_iterator = table->items[index], prev = NULL; _iterator != NULL; prev = _iterator, _iterator = _iterator->next);
_iterator = (ht_item*)malloc(sizeof(ht_item));
_iterator->key = (char*)malloc(200);
_iterator->value = (char*)malloc(200);
strcpy(_iterator->key, key);
strcpy(_iterator->value, value);
_iterator->next = NULL;
_iterator->prev = prev;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table, int dim) {
for(int i = 0; i < CAPACITY; i++)
{
if(table->items[i] != NULL)
{ ht_item *_iterator = (ht_item*)malloc(sizeof(ht_item));
for(_iterator = table->items[i]; _iterator != NULL;
_iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
} free(_iterator);
}
}
}
Made some changes in your code. Please read through the blocks containing // CHANGE HERE comment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
// CHANGE HERE - additional parameter, value to be used for modulo
unsigned long hash(char *str, unsigned int mod_value) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
// CHANGE HERE - use mod_value instead of CAPACITY
return stringsum % mod_value;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
return table;
}
if (value == NULL || key == NULL)
{
printf("Key or value is null\n");
return table;
}
// CHANGE HERE - pass table->dim to hash
unsigned long index = hash(key, table->dim);
printf("Index: %lu\n", index);
// CHANGE HERE - simplified the code a bit
ht_item* new_node = malloc(sizeof(ht_item));
new_node->key = malloc(200 * sizeof(char));
strncpy(new_node->key, key, 200);
new_node->value = malloc(200 * sizeof(char));
strncpy(new_node->value, value, 200);
// CHANGE HERE - if first node in index
if (table->items[index] == NULL)
{
table->items[index] = new_node;
return table;
}
ht_item *cur, *prev = NULL;
for(cur = table->items[index]; cur != NULL; prev = cur, cur = cur->next);
prev->next = new_node; // CHANGE HERE - it seems this line was missing
new_node->prev = prev;
new_node->next = NULL;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
printf("Table is null\n");
return;
}
// CHANGE HERE - change CAPACITY to dim
for(int i = 0; i < table->dim; i++)
{
//printf("i = %d [%d]\n", i, table->items[i] == NULL);
if(table->items[i] != NULL)
{
// CHANGE HERE - removed unnecessary malloc
ht_item *_iterator = NULL;
for(_iterator = table->items[i]; _iterator != NULL; _iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
}
}
}
}
The create_item function can and should be simplified.
I have put some comments inline.
HashTable* create_item(HashTable *table, char *value, char *key) {
// use modulo operator here, not in the hash function
unsigned long index = hash(key) % table->dim;
// nicer way of allocating
ht_item *insert = malloc(sizeof *insert);
// use strdup to avoid wasted memory and buffer overflows
insert->key = strdup(key);
insert->value = strdup(value);
// head insert rather than tail
insert->next = table->items[index];
table->items[index] = insert;
return table;
}
I dropped the use of the prev member. If you need that somewhere it's an exercise for you to add it. I don't think it's necessary for a simple hash table.

Segmentation Fault in A Doubly Linked List Display Function

So I have a program that takes an int for input, and inserts the integer into a doubly linked list where the functions are createQueue, enqueue, dequeue, display, peek, and destroyQueue. I have a main.c and a queue.h file but the problem doesn't lay in there, it's in the queue.c file. The problem is when I pipeline a test12.txt file and print to an output.txt with the following commands, enqueue 0 0 display, I get a segmentation fault. If I run just enqueue 0 0 in the test12.txt file there's no problem, it works just fine. My question is, am I dereferencing temp in display when it points to nothing when I write temp = temp->prev; or is that a valid call and my problem lies in the initialization of my temp node?
queue.c file:
#include "queue.h"
Queue_ptr createQueue() {
Queue_ptr s = (Queue_ptr)malloc(sizeof(Queue));
s->front = NULL;
s->back = NULL;
return s;
}
void enqueue(Queue_ptr s, element e) {
DN_ptr n = (DN_ptr)malloc(sizeof(DLLNode));
n->e = e;
if (s->front == NULL) {
n->next = NULL;
s->front = n;
s->back = n;
}else{
s->back->next = n;
n->prev = s->back;
s->back = n;
}
}
element dequeue(Queue_ptr s) {
DN_ptr temp = s->front->next;
element e = s->front->e;
free(s->front);
s->front = temp;
s->front->next = NULL;
s->front->prev = NULL;
return e;
}
int isEmpty(Queue_ptr s) {
if (s->front == NULL)
return 1;
else
return 0;
}
element peek(Queue_ptr s) {
return s->front->e;
}
void display(Queue_ptr s) {
DN_ptr temp = s->back;
while (temp) {
printf("%d\n", temp->e);
temp = temp->prev;
}
}
void destroyQueue(Queue_ptr s) {
DN_ptr temp = s->front;
DN_ptr next;
while (temp) {
next = temp->next;
free(temp);
temp = next;
}
free(s);
}
queue.h file:
#ifndef queue_h
#define queue_h
#include "stdheader.h"
//Structures
//element is content of a node.
typedef int element;
//_DLLnode is 1 link in a doubly linked list.
struct _DLLNode {
element e;
struct _DLLNode *next;
struct _DLLNode *prev;
};
typedef struct _DLLNode DLLNode;
typedef struct _DLLNode *DN_ptr;
//DLL is a series of links tracked by the head and back of the list.
struct _DLL {
DN_ptr front;
DN_ptr back;
};
typedef struct _DLL Queue;
typedef struct _DLL *Queue_ptr;
Queue_ptr createQueue();
void enqueue(Queue_ptr, element);
element dequeue(Queue_ptr);
int isEmpty(Queue_ptr);
element peek(Queue_ptr);
void display(Queue_ptr);
void destroyQueue(Queue_ptr);
#endif /* queue_h */
You do not set n->prev in enqueue when the queue is empty, neither do you set n->next when the queue is not empty.
dequeue corrupts the queue if it has more than 2 elements, and it crashes if it has only one element.
Here is a corrected version:
void enqueue(Queue_ptr s, element e) {
DN_ptr n = (DN_ptr)malloc(sizeof(DLLNode));
n->e = e;
n->next = NULL;
if (s->front == NULL) {
n->prev = NULL;
s->front = n;
s->back = n;
} else {
s->back->next = n;
n->prev = s->back;
s->back = n;
}
}
element dequeue(Queue_ptr s) {
DN_ptr temp = s->front->next;
element e = s->front->e;
free(s->front);
s->front = temp;
if (temp) {
temp->prev = NULL;
} else {
s->back = NULL;
}
return e;
}

Error in implementation of a stack with O(1) find-max/find-min?

I have implemented several functions for the Stack ADT. I am trying to find the max and min values in O(1) time and I have augmented my stack structure to serve this purpose. This is my code:
void mms_push(MMStack mms, int i) {
struct llnode *new = malloc(sizeof(struct llnode));
new->item = i;
if(mms->len!=0)
{
new->next = mms->topnode;
mms->topnode = new;
}
else
{
new->next = NULL;
mms->topnode = new;
}
if (mms->len == 0)
{
mms->topnode->minc = i;
mms->topnode->maxc = i;}
else
{
if(mms->topnode->maxc < i)
{
mms->topnode->maxc = i;
}
if(i<mms->topnode->minc)
{
mms->topnode->minc = i;
}
mms->len++;}
int mms_pop(MMStack mms) {
assert(mms);
int ret = mms->topnode->item;
struct llnode *backup = mms->topnode;
mms->topnode = mms->topnode->next;
mms->len--;
free(backup);
return ret;
}
My structures used are as below:
struct llnode
{
int item;
struct llnode *next;
int minc;
int maxc;
};
struct mmstack
{
int len ;
struct llnode *topnode;
};
typedef struct mmstack *MMStack;
I am not getting the correct value of max and min values. How do I correct the code so that I get the right value of max and min element in the stack?
Thanks in advance!
Take a look at this code:
if (mms->len == 0)
{
mms->topnode->minc = i;
mms->topnode->maxc = i;
}
else
{
if(mms->topnode->maxc < i)
{
mms->topnode->maxc = i;
}
if(i<mms->topnode->minc)
{
mms->topnode->minc = i;
}
}
Notice that in the else branch, you're reading the values of mms->topnode->minc and mms->topnode->maxc before you've initialized them. I think you meant to look at the values of mms->topnode->minc/maxc before you reassigned mms->topnode. To fix this, try doing something like this:
else
{
mms->topnode->maxc = mms->topnode->next->maxc;
mms->topnode->minc = mms->topnode->next->minc;
if(mms->topnode->maxc < i)
{
mms->topnode->maxc = i;
}
if(i<mms->topnode->minc)
{
mms->topnode->minc = i;
}
}
These extra two lines initialize the min and max values to the old max values before comparing against i, which should ensure that they get a value.
Hope this helps!
You're doing things a bit backwards — comparing i to the values in the new, uninitialised node after you have inserted it in the stack.
It's easier to first prepare the new node completely, and then link it into the stack.
Assuming that an empty stack has a NULL topnode:
void mms_push(MMStack mms, int i) {
struct llnode *new = malloc(sizeof(struct llnode));
new->item = i;
new->next = mms->topnode;
if (!mms->topnode)
{
new->minc = i;
new->maxc = i;
}
else
{
new->minc = min(mms->topnode->minc, i);
new->maxc = max(mms->topnode->maxc, i);
}
mms->topnode = new;
mms->len++;
}
I'm not sure if min and max are C99, but they're trivial to define.

Writing list to file

I have a problem with writing list to file. Please check my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct record
{
char name[30];
int score;
} record;
int score = 23;
char winner[30] = "gracz";
typedef struct el_list
{
record record;
struct el_list* next;
} el_list;
el_list *first = NULL;
int addrecord()
{
el_list *record;
record = (el_list*) malloc (sizeof(el_list));
record->next = NULL;
record->record.score = score;
strcpy(record->record.name, winner);
return record;
}
void addtolist(el_list** first)
{
el_list *pom, *tmp = addrecord();
if (*first == NULL)
*first = tmp;
else if ((*first)->record.score > tmp->record.score)
{
tmp->next = *first;
*first = tmp;
}
else
{
pom = (*first);
while((pom->next != NULL) && (pom->record.score < tmp->record.score))
pom = pom->next;
tmp->next = pom->next;
pom->next = tmp;
}
}
void save2file(el_list* first)
{
el_list *tmp;
FILE *hs = fopen("highscores.txt", "w");
if( hs == NULL)
perror("Blad z plikiem.");
else
{
tmp = first;
while(tmp != NULL)
{
fprintf( hs, "%d %s\n", score, winner);
tmp = tmp->next;
}
}
fclose(hs);
}
int main()
{
addtolist(&first);
save2file(&first);
return 0;
}
Probably I have problem with while in save2file.
Sorry for my English. ;)
You're saving score and winner, which are global variables unrelated to the current list item in tmp.
Also, for clarity's sake, you should open the output file in text mode, i.e. with fopen("highscores.txt", "wt").

Resources