C Having Trouble with Pointer Incrementing (I think) - c

Quite a simple error I guess but I get this error when trying to compile my C code:
error: expected identifier before '(' token
From this code where I am trying to set up structs for a hash table with linked lists for hash collisions:
typedef struct bN {
MEntry nestedEntry;
struct bN *next;
} bucketNode;
typedef struct bL {
bucketNode *first;
int bucketSize;
} bucket;
struct mlist {
bucket *currentTable;
};
And this code where I actually initialise the linked list:
MList *ml_create(void){
MList *temp;
if (ml_verbose){
fprintf(stderr, "mlist: creating mailing list\n");
}
if ((temp = (MList *)malloc(sizeof(MList))) != NULL){
temp->currentTable = (bucket *)malloc(tableSize * sizeof(bucket));
int i;
for(i = 0; i < tableSize; i++){
temp->(currentTable+i)->first = NULL; /**ERROR HERE*/
temp->(currentTable+i)->bucketSize = 0; /**ERROR HERE*/
}
}
return temp;
}

Your syntax is off. You mean:
temp->currentTable[i].first = NULL;
temp->currentTable[i].bucketSize = 0;

Change
temp->(currentTable+i)->first = NULL;
to be
(temp->currentTable+i)->first = NULL;

Related

Incompatible pointer type warning whit in self referencied structs, trying to implement a hash table

I'm trying to implement a hash table with pointers to a double-linked list that stores the information in C language. The problem is that i keep getting warnings from the compiler that I don't understand why. The warnings are all "warning: assignment from incompatible pointer type "
Here are my structs:
typedef struct stru_contacto_list{
char *nome;
char *email;
char *telefone;
struct stru_contacto_list *prev, *next;
}contacto_list;
typedef struct stru_contacto{
contacto_list *info;
struct stru_contact *next_hash;
}contacto_hash;
typedef struct{
contacto_hash **val;
}hash_tableC;
Here is some code for you to understand better what is hapening:
Initializing the hash table
void initContactos(hash_tableC *c){
int i;
c->val =
(contacto_hash**)malloc(sizeof(contacto_hash)*DEFAULTSIZE);
for(i = 0; i < DEFAULTSIZE; i++){
c->val[i] = NULL;
}
}
Here's some code from where I get the warnings, here im am trying to add a 'contact_hash' to the hash table by putting it in the head of the linked list associated to the index in the hash_table.
void addContact(){
int index, flag;
contacto_hash *novo =
(contacto_hash*)malloc(sizeof(contacto_hash));
contacto_list *novoL =
(contacto_list*)malloc(sizeof(contacto_list));
flag = addContactToList(novoL);
if (flag){
free(novo);
return;
}
novo->info = novoL;
novo->next_hash = NULL;
index = hashing(novoL->nome);
if (contactos->val[index] != NULL)
novo->next_hash = contactos->val[index]; /* THE WARNING*/
contactos->val[index] = novo;
}
Some other small piece of code where I get the same "warning : assignment from incompatible pointer type " :
contacto_hash* find(char *nome, int indice){
/*Returns the previous contact_hash i want to find*/
contacto_hash *atual, *prev;
if (contactos->val[indice] == NULL)
return NULL;
atual = contactos->val[indice];
prev = atual;
while (atual != NULL) {
if (strcmp(atual->info->nome, nome) == 0){
return prev;
}
prev = atual;
atual = atual->next_hash; /* THE WARNING */
}
return NULL;
}
The warning from the compiler is "warning: assignment from incompatible pointer type"

How can I get the address of a pointer for my linked list such that I can properly set it in a hashtable after removing an item in c?

When removing an element from a hashtable, I need to traverse through linked-lists for elements that collide. I am using pointer operations to do this, and my linked list is in the form of bucket_t. The problem I am facing is that when I try to save the location of the first ht->bucket[I], that value changes along with the others, so at the end of the function, my head is right at the spot of next and results in a segmentation fault. I am new to working with pointers like this in c, and I apologize if my explanation is bad, but I think the code is fairly simple for you guys to see what I am trying to achieve:
void ht_del(hashtable_t *ht, char *key) {
bucket_t *last=NULL, *next=NULL, *head=NULL;
unsigned long i;
for(i = 0; i < ht->size; i++){
head = ht->buckets[i];
next = ht->buckets[i];
while(next && next->key && strcmp(next->key,key)!=0){
last = next;
next = next->next;
printf("\nvisiting next\n");
printf("key = %s\n", head->key);
}
if(next && next->key && strcmp(next->key,key)==0){
printf("key found, removing key = %s, val = %s:", next->key, next->val);
free(next->key);
free(next->val);
if(next->next){
last->next = next->next;
printf("Last->next ->key = %s\n", last->next->key);
}
else{
free(next->next);
printf("end of the line\n");
}
free(next);
printf("head key = %s", head->key);
}
}
}
Additionally, to help understand the structs im using:
typedef struct hashtable hashtable_t;
typedef struct bucket bucket_t;
struct bucket {
char *key;
void *val;
bucket_t *next;
};
struct hashtable{
unsigned long size;
bucket_t **buckets;
};
How can I get the address of a pointer for my linked list such that I can properly set it in a hashtable after removing an item... ?
To remove a node from a linked list, keep track of the previous node.
for(i = 0; i < ht->size; i++){
bucket_t before_head = { .next = ht->buckets[i] }; // Only next member used.
bucket_t *previous = &before_head;
while (previous->next && strcmp(previous->next->key,key) != 0) {
previous = previous->next;
}
if (previous->next) { // match was found
// delete previous->next and its members allocations
bucket_t *node_after_match = previous->next->next;
free(previous->next->key);
free(previous->next->val);
free(previous->next);
// link previous to node after deletion.
previous->next = node_after_match;
// assign a potential new head of the list
ht->buckets[i] = before_head.next;
break; // exit for loop
}
}
As hinted by #Pablo, I'd expect a hash function instead of a for() loop to rapidly find the hash table index. Something like:
// for(i = 0; i < ht->size; i++){
i = hash(key)%ht->size;
void ht_del(hashtable_t *ht, char *key) {
unsigned long i;
i = hash(key)%ht->size;
bucket_t before_head = { .next = ht->buckets[i]};
bucket_t *previous = &before_head;
while(previous->next && strcmp(previous->next->key,key)!=0) {
previous = previous->next;
}
if(previous->next ) {
bucket_t *next = previous->next->next;
bucket_t *b = previous->next;
free(previous->next->key);
free(previous->next->val);
previous->next = next;
free(b);
ht->buckets[i] = previous->next;
}
}

how to initializing a hash table in C

I have a program in C that creates a hash table.
memset is Okay but, i want to initialize with for loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HSZ 127
#define HASHING(x) ((x)%HSZ)
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
void init(void){
int i;
//memset(hash_table,0,sizeof(hash_table));
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
}
void insert_hash(int value){
int key = HASHING(value);
struct node_t *newNode = (struct node_t*)malloc(sizeof(struct node_t));
newNode->val = value;
newNode->next = NULL;
if(hash_table[key] == NULL){
hash_table[key] = newNode;
} else {
newNode->next = hash_table[key];
hash_table[key] = newNode;
}
}
int delete_hash(int value){
int key = HASHING(value);
if (hash_table[key] == NULL)
return 0;
struct node_t *delNode = NULL;
if (hash_table[key]->val == value){
delNode = hash_table[key];
hash_table[key] = hash_table[key]->next;
} else {
struct node_t *node = &hash_table[key];
struct node_t *next = hash_table[key]->next;
while (next){
if (next->val == value){
node->next = next->next;
delNode = next;
break;
}
node = next;
next = node->next;
}
}
return 1;
free(delNode);
}
void PrintAllHashData()
{
printf("###Print All Hash Data###\n");
for (int i = 0; i < HSZ; i++){
if (hash_table[i] != NULL){
printf("idx : %d ", i);
struct node_t *node = hash_table[i];
while (node->next){
printf("%d ", node->val);
node = node->next;
}
printf("%d\n", node->val);
}
}
}
int main(void){
init();
insert_hash(1);
insert_hash(3);
insert_hash(128);
PrintAllHashData();
}
look at this code.
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
The IDE I am using does not throw up a compilation error when I compile the code, but during the execution the code faults and is terminated/haulted. I tried debugging the code, it faults at this line and is stopped, I think BAD ACCESS points to Segmentation Error.
then, I changed this line to
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
but, then I got the compilation error stating 'structure type require instead of 'struct node_t *'
I think that I don't understand clearly about struct in C.
How to fix this problem?
What you are dealing with is Undefined Behavior.
See, struct node_t *hash_table[HSZ];
So, hash_table is an array of HSZ (127) pointers of the data type struct node_t.
When you do,
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
hash_table[0] to hash_table[126] pointers are not pointing to anything.
So, each of them (or all of them) should be initialized first to point to an object of the type struct node_t and then you can initialize them. For that matter, Using a memset does not cause a problem because memset is filling the contents of the pointers with all zeros. There is difference between filling the pointers with all zeros and filling all zeros to the memory pointed by pointers.
Trying this,
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
is plain wrong.
To fix the issue you are facing, you need to allocate memory dynamically using malloc. You can do the in your for loop.
for(i = 0; i < HSZ; i++)
{
//Allocate memory of the size struct_node_t
hash_table[i] = malloc(sizeof(struct node_t)); //Do not cast!
//Check if memory is allocated
if(hash_table[i] == NULL)
{
//Memory not allocated, set some error state to handle and break
break;
}
//Initialize to zero
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
when you have *hash_table[HSZ], this varible hash_table is a pointer. so whatever your action is , use hash_table-> ,syntax for pointer, mean point to somewhere.
a suggestion that when you use pointer you should always allocate memory hash_table[i] = malloc(sizeof(struct node_t));
struct node_t hash_table;
but if you initilize your varible like this, you can use hash_table.val = 0
so the way of assign value depend on how you declare your varibles
struct node_t *hash_table[HSZ];
gives you an array of pointers that are unset (i.e. not pointing to anything)
void init(void) {
int i;
// memset(hash_table,0,sizeof(hash_table));
for (i = 0; i < HSZ; i++) {
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
tries writing to your invalid pointers which gives undefined behavior.
Either make the array an array of structs (instead of pointers):
struct node_t hash_table[HSZ];
...
/* note use of . instead of -> since we have structs not pointers */
hash_table[i].val = 0;
or allocate the necessary structs so the array points to something:
for (i = 0; i < HSZ; i++) {
hash_table[i] = malloc(sizeof(struct node_t));
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}

initialization of flexible array of struct pointers in a struct in c

I'm learning hashtable data structures and I want to make a hashtable with a flexible length array of pointers to struct Link (linked list pieces), so that hashtable initialization will set the array to be a length input into the initialization function.
At first I was getting the error "flexible array not at the end of struct". When its at the end (as shown) the program crashes (but it still compiles). This is my code:
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
int numberOfEntries;
int numberOfBuckets;
Link *Table[];
} HashTable;
HashTable *hashtableInit(int size){
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
It works if I set the array to a constant and input the same value into the init function:
#define SIZE 11
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
Link *Table[SIZE];
int numberOfEntries;
int numberOfBuckets;
} HashTable;
HashTable *hashtableInit(int size){ // works if SIZE is passed into function as size parameter
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
The second code block works perfectly. Any insights would be greatly appreciated. Thanks for your time.
Chris
You should allocate memory as
HashTable *newHT = malloc(sizeof *newHT + size * sizeof newHT->Table[0]);
Your
HashTable *newHT = malloc(sizeof(HashTable));
is wrong, because no space is given for the flexible array member. Should probably be
HashTable *newHT = malloc(sizeof(HashTable)+size*sizeof(Link*));

linked list && structures

I would like to know if design of my program is correct, as well as to understand if my commented area is doing what it supposed to be doing. I get these compile errors that are associated probably with commented segments of my code, and I would lie to receive some help. THANKS!
part1.c:15:6: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'insert'
part1.c: In function 'main':
part1.c:43:14: error: incompatible types when assigning to type 'struct point' from type 'int'
part1.c:49:44: error: invalid type argument of '->' (have 'struct point')
part1.c:49:59: error: invalid type argument of '->' (have 'struct point')
part1.c:55:5: error: incompatible type for argument 1 of 'free'
/usr/include/stdlib.h:488:13: note: expected 'void *' but argument is of type 'struct point'
char *chars[3]= {"a","b","c"};
int nums[3]= {5,8,9};
struct point {char *letter;
int number;
struct point *next;};
struct point* insert(struct point list[],char *rqdLetters, int rqdNums)
{
struct point *new;
new = (struct point*)malloc(sizeof(struct point));
if(new == NULL)
fprintf(stderr,"error!");
new->letter = rqdLetters;
new->number = rqdNums;
new->next = head;
head = new;
//not sure if i'm returning the a pointer to the start of new list
return head;
}
int main(int argc, char **argv)
{
//not sure if i need to declare these here or in the insert
struct point list[3];
struct point *head = NULL;
struct point *next;
struct point *new;
int i;
for (i = 0; i < 3; i++)
{
//return result put back into the pointer to the start of the list
head[i] = insert(list[i], chars[i], nums[i]);
}
int j;
for(j = 0; j < 3; j++)
{
printf("letter %s and number %d\n", list[j]->letter, list[j]->number);
}
int z;
for(z = 0; z < 3; z++)
{
free(list[z]);
}
return 0;
}
At a glance, there are several issues with your code. Firstly, you're not declaring your variables correctly.
new = list;
should be:
struct point* new;
Your function signature also looks a little suspect. If you're returning a pointer to your data structure, it should be something like:
struct point* insert(...) { ... }
At a more general level, I does seem like your idea of a linked list may be a little off. To represent a list, you should only need to hold on to the head and tail of the list, instead of keep an array of your points.
It usually helps if you create a data structure to hold these pointers. You can then pass this structure around to functions that operate on the list e.g. the insert() function.
As a quick example (untested):
struct node {
struct node *next;
char letter;
int number;
}
struct list {
struct node *head;
struct node *tail;
}
/* create a new list */
struct list* list_new(void) {
struct list *L = malloc(sizeof(struct list));
L->head = NULL;
L->tail = NULL;
}
/* add a new node to the list */
void list_insert(struct list *list, char in_letter, int in_number) {
struct node *node = malloc(sizeof(struct node));
node->letter = in_letter;
node->number = in_number;
node->next = NULL;
if (list->head == NULL) { /* empty list */
list->head = node;
list->tail = node;
} else { /* append to list */
list->tail->next = node;
list->tail = node;
}
}
You can then use it as such:
int i;
char chars[3]= {"a","b","c"};
int nums[3]= {5,8,9};
struct list *mylist = list_new();
for (i = 0; i < 3; i++)
{
list_insert(mylist, chars[i], nums[i]);
}
In response to:
... and i am not sure if i am supposed to declare it inside insert or main, i did in the main however
This depends on where you intend to use the variables and the intended lifespan of these variables. As stated in the comments above, you might want to polish up on your understanding of scoping rules.

Resources