Error compiling hash table implementation in C - c

I have a file with ~6 million records (key value pairs) that I am trying to store in a hash table. However, I am falling at the first fence. The program will not compile and I have not even attempted to read in the records yet.
Firstly, when trying to initialise the whole array I am getting the following error:
31: error: incompatible types when assigning to type ‘struct node’ from type ‘void *’
Perhaps I should make everything inside my struct node equal to null? But is it not better that the array locations are equal to null?
Also, in my insert function, when checking if the array location is null I get this error:
invalid type argument of unary ‘*’ (have ‘struct node’)
How do I check if the array location is empty? This error is from lines 63, 65, 69, 71, 76
I have read many posts on here (including Why whole structure can not be compared in C, yet it can be copied?) but cannot get my code to compile. Apologies if this is basic stuff.
Full code I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_SIZE 1000000
struct node{
unsigned long long key;
float value;
struct node *next;
};
struct node *ebv_hash = NULL;
unsigned long long hash(unsigned long long);
void insert(unsigned long long, float);
int main(int argc, char *argv[]){
FILE *ebv_fp;
ebv_fp=fopen(argv[1], "r");
ebv_hash = malloc(HASH_SIZE * sizeof(struct node));
for(unsigned long long a=0; a <=HASH_SIZE; a++){
*ebv_hash[a]=NULL;
}
/* Code to read in data I have not written yet */
fclose(ebv_fp);
free(ebv_hash);
return 0;
}
unsigned long long hash(unsigned long long ani_id){
return (ani_id % HASH_SIZE);
}
void insert(unsigned long long nkey, float nvalue){
struct node *nani = malloc(sizeof(struct node));
unsigned long long hash_ind;
nani->key=nkey;
nani->value=nvalue;
nani->next=NULL;
hash_ind = hash(nkey);
if(ebv_hash[hash_ind] == NULL){
ebv_hash[hash_ind] = nani;
}else{
struct node *p = malloc(sizeof(struct node));
p = ebv_hash[hash_ind];
while(p->next != NULL){
p = p->next;
}
p->next = nani;
}
}

You've declared
struct node* ebv_hash = NULL;
and used
ebv_hash = malloc(HASH_SIZE * sizeof(struct node));
This means that you're going to get an array of struct node.
I think what you want is an array of pointers to struct node. That would look like this:
struct node** ebv_hash = NULL;
ebv_hash = malloc(HASH_SIZE * sizeof(struct node*));
for(int i=0;i<HASH_SIZE;i++)
ebv_hash[i] = NULL;
Then when you need a node i, you malloc yourself one and set the appropriate ebv_hash[i].

Related

C - Not working (node) structures in main function (intentionally avoiding use of singly linked list implementation)

I'm trying to create a singly linked list without implementation. I'm doing this just to gain some deeper understanding on how structures work. I just want to create 2 nodes in the main function and link them. I could do that using typedef in the declaration of structures and by making the implementation, but that's not what I want (I can do that successfully).
I've written some code, but an error occurs at line 27 (the same problem appears at lines 29, 30 and 33). I know the explanation for this problem is rather simple, but I couldn't find it, either on my mind or on the web (or books). I'd appreciate any assistance in this problem. I've been programming just for the last year.
I thought in asking for help in CodeReview, but accordingly, to their FAQ, that wasn't the place to ask for help with this kind of problem.
Errors are:
27:11: error: incompatible types when assigning to type 'struct NODO ' from type 'struct NODO'
E.sig = F;
Same problem with the other lines. Everything is in the same file (.c).
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
struct NODE {
int data;
struct NODE *next;
};
struct LIST {
struct NODE *first;
struct NODE *last;
int size;
};
void main(){
struct NODE E;
struct NODE F;
struct LIST L;
E.data = 1;
E.next = NULL;
F.data = 2;
F.next = NULL;
E.next = F; // line 27
L.first = E; // line 29
L.last = F; // line 30
struct NODE *ptr;
ptr = E; // line 33
while(ptr != NULL){
printf("%i\n", ptr->data);
ptr = ptr->next;
}
}
The problem is that you are trying to assign an object to a pointer. You should assign the address of your node and note the node object itself.
Try E.next = &F; and same for all the others.
A pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location. So you have to provide the address of the memory location .In C address of a variable is derived using & operator.
Modified code :-
#include <stdio.h>
#include <stdlib.h>
struct NODE {
int data;
struct NODE *next;
};
struct LIST {
struct NODE *first;
struct NODE *last;
int size;
};
int main(){
struct NODE E;
struct NODE F;
struct LIST L;
E.data = 1;
E.next = NULL;
F.data = 2;
F.next = NULL;
E.next = &F; // not E.next = F;
L.first = &E; // not L.first = E;
L.last = &F; // not L.last = F;
struct NODE *ptr;
ptr = &E; // not ptr = E;
while(ptr != NULL){
printf("%i\n", ptr->data);
ptr = ptr->next;
}
return 0;
}
Recommended to use int main() instead of void main().
Output :-
1
2
I've found the solution or at least some additional information that led me towards the solution minutes after sending the question to SO.
In Wikipedia (https://en.wikipedia.org/wiki/Struct_(C_programming_language)#Pointers_to_struct) I've found the next snippet of code:
struct point {
int x;
int y;
};
struct point my_point = { 3, 7 };
struct point *p = &my_point; /* To declare and define p as a pointer of type struct point,
and initialize it with the address of my_point. */
My mistake was using the pointer to point to the structure and not to the structure's address. Pointers can point only to addresses (they store its value), they cannot point to objects.

dereferencing error in linked list - not typedef error

I can't find my dereferencing error to save my life. As far as I can see I've got all my declarations where they need to be and can't see where I have defined a bad structure.
EDIT: the paste is missing a ton of the code, but it includes all of the code that uses the pointers. everything else is checking to make sure the file is the right file, right location, error handling, etc.
typedef struct list{
int pid;
char *name;
struct list* link;
}LIST;
void begin(FILE *file, char *argv[])
{
struct LIST *root, *p, *tail;
struct utmp x[BUFF];
root = NULL;
char *name;
int c;
int i;
struct utmp hold;
int pid;
tail = malloc(sizeof(LIST));
int logins = 0;
int logouts = 0;
for (i=0;i<=BUFF;i++)
{
c = fread(x, sizeof(struct utmp), BUFF, file);
if (strcmp(x[i].ut_user, argv[1]) == 0)
{
if (x[i].ut_type == 7)
{
hold = x[i];
logins++;
pid = x[i].ut_pid;
name = hold.ut_user;
p = create(pid, name); //<--Line 129
if (root == NULL)
{
root = tail = p;
}
else
{
tail->link = p; //<---Line 136
tail = p;
}
printf("%d\n", p->pid); //<---Line 139
}
}
if (x[i].ut_pid == pid && x[i].ut_type == 8)
{
pid = 0;
logouts++;
}
}
LIST *create(int pid, char *name)
{
LIST *p;
p = malloc(sizeof(LIST));
p->pid = pid;
p->link = NULL;
p->name = name;
return p;
}
The error:
main.c: In function ‘begin’:
main.c:129:10: warning: assignment from incompatible pointer type [enabled by default]
main.c:136:9: error: dereferencing pointer to incomplete type
main.c:139:24: error: dereferencing pointer to incomplete type
Your issue is with confusing how to use structs and typedefs. Your definition
typedef struct list{
...
}LIST;
creates 2 data types the structure struct list and its typedef equivalent LIST. Then when you declare your variables, you use struct LIST, which isn't defined. This is generating all 3 of your errors. The compiler is assuming that you are defining this struct somewhere else. The reason that people use typedef is to make the later use of struct unnecessary.

Pointers and structs

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
#define HASH_SIZE 100
// prototype
int hash(char *word);
// counter
int counter;
// node
typedef struct
{
char *word;
node *next;
} node;
// hash table
node *hashtable[HASH_SIZE];
bool
load(const char *dictionary)
{
// open the dictionary
FILE *dict = fopen(dictionary, "r");
if(dict == NULL)
{
printf("Could not open %s.\n", dictionary);
return false;
}
// set all values in the hash table to null
for(int i = 0; i < HASH_SIZE; i++)
{
hashtable[i] = NULL;
}
// set the counter to 0
counter = 0;
// iterate through the words in the dictionary
while (!feof(dict))
{
// get word into a string
char gotcha[LENGTH];
fscanf(dict, "%s", gotcha);
// declare a node and allocate memory
node n;
n.word = malloc( strlen(gotcha)*sizeof(char) );
// save the word into the node
strcpy(n.word, gotcha);
// hash the word, baby!
int hash_value = hash(n.word);
// start saving addresses to the hashtable
n.next = hashtable[hash_value];
hashtable[hash_value] = &n;
//test
int len = strlen(n.word);
printf("%s\n", n.word);
printf("%i\n", len);
// that's one more!
counter++;
}
fclose(dict);
return true;
}
I am receiving the following two errors on these two lines of code:
n.next = hashtable[hash_value];
hashtable[hash_value] = &n;
dictionary.c:89:16: error: assignment from incompatible pointer type [-Werror]
dictionary.c:90:31: error: assignment from incompatible pointer type [-Werror]
How do I save pointer values in these two places? I am new to this, so please bear that in mind. :)
In your structure, the type node is not yet defined. Change it to use the structure tag:
typedef struct node
{
char *word;
struct node *next;
} node;
This:
typedef struct
{
char *word;
node *next;
} node;
is a syntax error. The node *next; occurs before the end of the typedef that creates node as a type. If your compiler for some reason accepted this, it probably thinks there are 2 different types called "node" now, which explains why one of them isn't compaible with the other. You should give up on that typedef silliness (structs generally shouldn't be typedef'ed) and just use
struct node
{
char *word;
struct node *next;
};
Define typedef names of structs before defining the structs. This allows mutually referring structs without concern for order and doesn't require inconsistent definitions, sometimes with the struct keyword and sometimes without it. Note that in C++ you can do away with the typedef line entirely:
typedef struct node node;
struct node
{
char* word;
node* next;
};

incompatible pointer type error C

So I'm trying to implement a cache in C. I have included a very slimmed down version of my code.
I keep getting this error:
prog.c: In function ‘addtolist’:
prog.c:29: warning: assignment from incompatible pointer type
prog.c:40: warning: assignment from incompatible pointer type
prog.c: In function ‘main’:
prog.c:72: warning: assignment from incompatible pointer type
from this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct node_
{
char * word;
int filenumber;
struct node * next;
};
typedef struct node_ * node;
node createnode()
{
node head;
head = malloc(sizeof(struct node_));
head->word = NULL;
head->next = NULL;
return head;
}
unsigned int addtolist(node head, char * word, unsigned int limit, int fileno)
{
unsigned int templimit = limit;
node temp;
node temphead = head;
while(temphead->next != NULL)
{
temphead = temphead->next;
}
temp = malloc(sizeof(struct node_));
temp->word =(char*) malloc(strlen(word)+ 1);
strcpy(temp->word, word);
temp->next = NULL;
temp->filenumber = fileno;
templimit = templimit - (strlen(word) + 1) - sizeof(struct node_)- sizeof(int);
printf("templimit is size %u\n", templimit);
if (templimit < limit && templimit > 0)
{
temphead->next = temp;
limit = limit - strlen(word) - 1 - sizeof(struct node_)- sizeof(int);
return limit;
}
else
{
free(temp->word);
free(temp);
return 0;
}
}
int main()
{
node newlist = createnode();
int i = 0;
unsigned int limit = 65;
unsigned int temp = limit;
while(temp > 0 && temp <= limit)
{
temp = addtolist(newlist, "Hello", temp, i);
i++;
printf("new limit is - \t%u\nfilenumber is - \t%d\n", temp,i);
}
node ptr = newlist;
while(ptr->next != NULL)
{
printf("node %d contains the word %s\n", ptr->filenumber, ptr->word);
ptr = ptr->next;
}
return 1;
}
I honestly can't figure out what I'm doing wrong... My logic was that, since I was typedef'ing my struct as a pointer, after I created the struct in memory, I would be able to easily step through the ensuing list. Where was the flaw in my logic?
EDIT the initial problem was fixed (I forgot an underscore in my type declaration for struct node_ next;.
Now I'm having another problem: when I try to step through the list at the bottom of my code to print out the words contained in the list, I'm basically not able to step through the list. I keep outputting:
templimit is size 43
new limit is - 43
filenumber is - 1
templimit is size 21
new limit is - 21
filenumber is - 2
templimit is size 4294967295
new limit is - 0
filenumber is - 3
node 0 contains the word (null)
node 0 contains the word Hello
For some reason, it seems that my program isn't storing my changes to my list in memory after the first iteration. Any ideas on what I'm doing wrong?
Once again, any help would be appreciated, and thanks.
Inside your structure definition you have struct node without the underscore.
you'd better have a forward declaration
typedef struct node node;
and then declare your structure
struct node {
...
node *next;
};
no need to have this underscore stuff and hiding the * in a typedef. That only makes you mix things up easily.
String literals "like this" have type const char*, not char*, because they're immutable.
Fix your declarations to have const char* and the warnings will go away.
I think the struct member 'next' has to be declared as a (node_ *) type. As written it is currently (node_ **)

Hashtable in C using linked lists

I'm new to C been at it about two weeks, hitting a few problems with linked lists and hash tables. The compilier is throwing a few errors:
I've tried to mark these in the source code.
finddupl.c: In function 'main':
finddupl.c:35:5: warning: assignment from incompatible pointer type
finddupl.c:37:3: warning: passing argument 1 of 'ml_lookup' from incompatible pointer type
mlist.h:19:9: note: expected 'struct MList *' but argument is of type 'struct MList *'
mlist.c: In function 'ml_lookup':
mlist.c:63:37: warning: assignment from incompatible pointer type
mlist.c: In function 'ml_add':
mlist.c:78:9: error: request for member 'hashtable' in something not a structure or union
mlist.c:90:12: warning: assignment from incompatible pointer type
Can anyone guide me in the right direction here, I've been at this for a few hours
Not loving C so far :p
I've left out the mentry.c and the c file with the main function, I've tested both of these before I tried to write the hash table.
Mentry.h
#ifndef _MENTRY_INCLUDED_
#define _MENTRY_INCLUDED_
#include <stdio.h>
typedef struct mentry {
char *surname;
int house_number;
char *postcode;
char *full_address;
} MEntry;
/* me_get returns the next file entry, or NULL if end of file*/
MEntry *me_get(FILE *fd);
/* me_hash computes a hash of the MEntry, mod size */
unsigned long me_hash(MEntry *me, unsigned long size);
/* me_print prints the full address on fd */
void me_print(MEntry *me, FILE *fd);
/* me_compare compares two mail entries, returning <0, 0, >0 if
* me1<me2, me1==me2, me1>me2
*/
int me_compare(MEntry *me1, MEntry *me2);
#endif /* _MENTRY_INCLUDED_ */
mlist.h
#ifndef _MLIST_INCLUDED_
#define _MLIST_INCLUDED_
#include "mentry.h"
typedef struct mlist MList;
extern int ml_verbose; /* if true, prints diagnostics on stderr */
/* ml_create - created a new mailing list */
struct MList *ml_create(void);
/* ml_add - adds a new MEntry to the list;
* returns 1 if successful, 0 if error (malloc)
* returns 1 if it is a duplicate */
int ml_add(MList **ml, MEntry *me);
/* ml_lookup - looks for MEntry in the list, returns matching entry or NULL */
MEntry *ml_lookup(struct MList *ml, MEntry *me);
#endif /* _MLIST_INCLUDED_ */
mlist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mentry.h"
#include "mlist.h"
#define HASHSIZE 101
struct Mlist_node{
MEntry *me;
MEntry *next;
int size;
};
struct Mlist_head{
struct Mlist_node *head;
struct Mlist_node *tail;
};
struct MList{
int size;
struct Mlist_head hashtable[HASHSIZE];
};
struct MList *ml_create(void){
struct MList *m;
struct Mlist_head *h;
int i;
if ((m = ( struct MList *)malloc(sizeof(struct MList))) != NULL){
if ((h = (struct Mlist_head *)malloc(sizeof(struct Mlist_head))) != NULL) {
for (i = 0; i < HASHSIZE; i++) {
h = &(m->hashtable[i]);
h->head = NULL;
h->tail = NULL;
}
printf("worked");
return m;
}
}
printf("fail");
return NULL;
}
MEntry *ml_lookup(struct MList *ml, MEntry *me){
struct Mlist_node *mn;
struct Mlist_head *mh;
if ((mn = (struct Mlist_node *)malloc(sizeof(struct Mlist_node))) != NULL) {
if ((mh = (struct Mlist_head *)malloc(sizeof(struct Mlist_head))) != NULL) {
unsigned hashval = me_hash(me,HASHSIZE);
printf("%d",hashval);
mh=&(ml->hashtable[hashval]);
for (mn = mh->head; mn != NULL; mn = mn->next) //LINE 63 ERROR
if (me_compare(mn->me, me) == 0)
return me; /* found */
}
}
return NULL;
}
int ml_add(MList **ml, MEntry *me){
unsigned hashval;
struct Mlist_head *mh;
struct Mlist_node *mn;
hashval = me_hash(me,HASHSIZE);
mh = ml->hashtable[hashval]; //LINE 78 ERROR
if ((mn = (struct Mlist_node *)malloc(sizeof(struct Mlist_node))) != NULL){
mn->me=me;
if(mh->head==NULL){
mh->head=mn;
mh->tail=mn;
mn->next=NULL;
}
else{
mn = mh->tail;
mn->next=me;
mh->tail=me; /LINE 90 ERROR
}
return 1;
}
else{
printf("failed to allocate memory");
return 0;
}
/* not found */
}
Look into how you're forward declaring MList in mlist.h. You use the syntax
typedef struct mlist MList;
This looks a little off to me. You're declaring a type of name MList. Note that with the above style of declaration, the compiler expects to see "struct mlist" or just the type name's MList when referring to this struct. (This question may be helpful to you). However later on you definen a struct MList as follows:
struct MList{
int size;
struct Mlist_head hashtable[HASHSIZE];
};
Which makes the compiler expect afterwords to see things referred to with "struct MList". But in your fwd declaration, you just said that plain old "MList" without the struct is ok. The compiler may or may not be able to make sense of this confusion between the fwd declaration and your definition. Its made worse in that one is a tag name of the struct and the other is the struct's canonical name. This kind of thing makes my spidy sense tingle that something could be off and causing confusion between you and the compiler.
I would just change how you forward declare to be consistent with how Mlist is used and see if that helps you. To do this change the above line to:
struct MList;
(then notice in mlist.h how you inconsistently use the struct keyword when referring to MList. Sometimes you do and sometimes you don't. this may also be causing problems w/ confusing your compiler. If you change to the above fwd declaration, use struct MList, not just MList)
In other news, for:
mlist.c:63:37: warning: assignment from incompatible pointer type
You're assigning a MEntry to a MNode, which are of different types, so I would expect you to get the warning you're getting.

Resources