Initializing C struct using pointer to pointer - c

I'm working on creating a hash table implementation for an assignment. I've defined my hashtable as struct as follows:
typedef struct hashtable {
int size;
int entries;
int table*; // pointer to table. Each entry will point to linked list
// of key-value nodes
} hashtable;
I have to initialize the hashtable struct in a method using double pointers, e.g.:
void init(hashtable** ht) {
...
}
I've written a basic implementation below:
#include <stdio.h>
#include <stdlib.h>
typedef struct hashtable {
int size;
int entries;
int table*; // pointer to table. Each entry will point to linked list
// of key-value nodes
} hashtable;
void init(hashtable**);
void init(hashtable** ht) {
*ht = (hashtable *) malloc( sizeof(hashtable) );
*ht->size = 3;
}
int main(){
hashtable *t = NULL;
init(&t);
printf("t.size: %i", t->size);
}
However, I keep getting the following compile error:
ll.c:19:8: error: member reference base type 'hashtable *' (aka 'struct hashtable *') is not a
structure or union
*ht->size = 3;
~~^ ~~~~
1 error generated.
So I'm confused by the following:
1. I'm not sure how to create a new struct in the init function when being passed a pointer to pointer.
2. After allocating the struct, how do I modify the struct member attributes?

This is just a operator precedence problem.
The compiler processes -> before the *. Therefore, it tries to access the size member of struct hashtable ** which is not possible.
The code compiles if you exchange *ht->size with (*ht)->size.

You have 2 errors in your code :
int table* --> int *table - Declare pointer to integer
*ht->size --> (*ht)->size - Imp to put brackets when you are not sure of operator precedence

That's a good start, and others have addresses the primary issues in your code. However, I would suggest a minor tweak:
#include <stdio.h>
#include <stdlib.h>
typedef struct hashtable {
int size;
int entries;
int table*; // pointer to table. Each entry will point to linked list
// of key-value nodes
} hashtable;
// note: freeing the hashtable is a caller responsibility!
hashtable *new_hashtable() {
hashtable *ht = malloc( sizeof(hashtable) );
ht->size = 3; // since ht is only a single pointer, no need for (*ht)->foo
return ht;
}
int main(){
hashtable *ht = new_hashtable();
printf("ht.size: %i", ht->size);
free(ht);
}

The problem is that
-> has higher precedence than * in C as you can see from here
using precedence rules *ht->size translates to *(ht->size). That should make clear the reason why you get the error. Another way to see it is
*(ht->size)=(*(*ht).size)
Fix this using parenthesis as follows: (*ht)->size
There is another issue in the definition of hashtable:
int table*; won't compile. Use int *table; instead to declare a pointer to int?

Thanks all for the quick response. For future reference, here's a quick update of the original code with solutions:
#include <stdio.h>
#include <stdlib.h>
typedef struct hashtable {
int size; // size of hash table
int entries; // number of slots allocated in table
int *table; /* pointer to table. Each entry will point to linked list
of key-value nodes */
} hashtable;
void init(hashtable**);
void init(hashtable** ht) {
*ht = (hashtable *) malloc( sizeof(hashtable) );
(*ht)->entries = 0;
(*ht)->size = 3; //replace this with better init size, ideally a prime number
(*ht)->table = malloc( (*ht)->size * sizeof(int));
}
int main(){
hashtable *t = NULL;
init(&t);
t->table[2] = 3;
printf("t.size: %i \n", t->size);
printf("t.arr:[2] %i \n", t->table[2]);
free(t);
}

Related

How to assign two void* C

I create in main.c an "hashmap" struct. it contains 6.000.000 "node" structs. i have to insert my elements by insert function. I didn't write it because it's not my trouble. If u need it I'll write it. Btw, the insert function is a generic function because data I need to insert every data type.In this case I insert a couple <key,value> of Integer. My trouble is : I have to make a function that return all key present in the hashmap t. In this function I have two parameters, both of them are void*. Key parameters in the hashmap are void*. The array that will contain all my keys, is void*. My aim is to put all my keys in this array and return it, but this is not possible ``` arr[j] = list->key; arr[j] = list->key;, the compiler gives me this error: incomplite type of void is not assignable*. Is there a way to resolve this thing?
library.c
struct node{
void* key;
void* val;
struct node *next;
struct node *prev;
};
struct hashmap{
int size;
struct node **list;
};
void recoverkey(struct hashmap *t, void *arr){
int j=0;
for (int i = 0; i < t->size; ++i) {
struct node *list = t->list[i];
while(list){
if(list->key!=NULL) {
arr[j] = list->key;
j++;
}
list = list->next;
}
}
}
main.c
#define SIZEFILE 6000000
int main(){
struct hashmap *t; // create hashmap
insert(); // I insert elements in the hashmap
int *arrRec;
arrRec = malloc(SIZEFILE*sizeof(int));
recoverkey(t,arrRec);

Cannot allocate dynamic array on C

Im trying to create a graph structure on C but I got some issues. First, Im getting 2 compilation errors:
main.c:18:19: error: member reference type 'node' is not a
pointer; did you mean to use '.'?
graph[index]->start = NULL;
~~~~~~~~~~~~^~
.
main.c:18:27: error: expression is not assignable
graph[index]->start = NULL;
~~~~~~~~~~~~~~~~~~~ ^
2 errors generated.
compiler exit status 1
I cannot figure out what Im doing wrong. I tried to create an array of nodes* but the compiler doesn't recognize it as a pointer for some reason. It's like malloc doesn't work. Also, I can't manage to acess edge* fields because it's like the array of nodes* is non-existent.
#include <stdio.h>
#include <stdlib.h>
#define maxNodes 4
typedef struct edge {
int target;
struct edge* next;
} edge;
typedef struct {
edge* start;
} node;
void initializeGraph(node* graph) {
graph = (node *) malloc(maxNodes * sizeof(node));
for(int index = 0; index < maxNodes; index++) {
graph[index]->start = NULL;
}
}
int main(void) {
node test;
initializeGraph(&test);
}
Im trying to initialize my structure. Any help is appreciated.
You have a large number of problems in your short example code. As to your error, that is covered by #dbush's answer and [...] serves as a dereference on your pointer making the '.' (dot) operator proper instead of the -> arrow operator.
Next, you cannot declare a node with static storage duration in main() and pass its address for allocation in your function. When you declare node test; all storage is already provided on the stack. You can't then pass that address to your function and allocate additional memory for that struct.
If you intend to have more than one node, then you can either declare an array with static storage duration in main(), or you must declare a pointer in main() and allocate in your function. To make that allocation visible in main(), as noted in my comment, you can either (1) make the return type node * and return a pointer to the allocated block for assignment in the caller, or (2) make the parameter node** and pass the address of your pointer as the parameter.
Putting that altogether and choosing option (1) above, you could do:
#include <stdio.h>
#include <stdlib.h>
#define maxNodes 4
typedef struct edge {
int target;
struct edge* next;
} edge;
typedef struct {
edge* start;
} node;
node *initializeGraph (void) {
node *graph = malloc(maxNodes * sizeof *graph);
if (!graph)
return NULL;
for (int index = 0; index < maxNodes; index++) {
graph[index].start = NULL;
}
return graph;
}
int main (void) {
node *test = initializeGraph();
if (!test)
fputs ("error: initialization failed.\n", stderr);
else
puts ("initialization succeeded");
}
Example Use/Output
$ ./bin/graphinit
initialization succeeded
Allocating For Each test[i].start
Before you can make use of any of the start pointers, you must allocate storage for a struct edge and assign the beginning address for that block of memory to each of your test[i].start pointers. You can do that in your same initializeGraph() function by allocating where you currently set the pointers NULL, e.g.
node *initializeGraph (void)
{
node *graph = malloc(maxNodes * sizeof *graph);
if (!graph)
return NULL;
for (int index = 0; index < maxNodes; index++) {
graph[index].start = malloc (sizeof *graph[index].start);
if (!graph[index].start)
return NULL;
}
return graph;
}
You can then assign a value to the target in each. Extending the earlier example, you could do:
int main (void) {
node *test = initializeGraph();
if (!test)
fputs ("error: initialization failed.\n", stderr);
else
puts ("initialization succeeded");
for (int i = 0; i < maxNodes; i++)
test[i].start->target = i;
puts ("targets filled");
}
Example Use/Output
$ ./bin/graphinit
initialization succeeded
targets filled
(don't forget to free the memory you allocate when it is no longer needed)
Look things over and let me know if you have further questions.
The array index operator [] implicitly dereferences a pointer. The syntax a[b] is exactly the same as *(a + b).
This means that graph[index] has type node, not node *. So use . instead of -> as the error message suggests.
graph[index].start = NULL;

First element in a double pointer to struct is jiberrish

I am creating a simple array of structures in C, but the first structure is always jibberish. How do i fix this?
I have tried to set the first element of the double pointer to struct in many ways but it always fails.
This is my graph.h file:
#ifndef GRAPH_H
#define GRAPH_H
#include "set.h"
typedef struct urlNode * URLList;
typedef struct GraphRep * Graph;
struct urlNode {
int id;
char* URL_NAME;
URLList next; // link to next node
};
struct GraphRep {
int nV;
URLList * collections;
};
Graph newGraph(Set s);
int nameToId(Graph g, char *name);
void showGraph(Graph g);
#endif
And my newGraph(Set s) function looks like this:
Graph newGraph(Set s){
int size = nElems(s);
Graph new_graph = malloc(sizeof(struct GraphRep));
if (new_graph == NULL) {
printf("ERROR: COULDNT ALLOCATE GRAPH\n");
}
new_graph->nV = size;
char *name = getNextVal(s);
// THIS IS THE NODE TO BE ADDED TO THE GRAPH
URLList list_to_add = malloc(sizeof(struct urlNode));
list_to_add->URL_NAME = strdup(name);
list_to_add->id = 0;
list_to_add->next = NULL;
// HERE I ADD THE NODE TO THE GRAPH.
new_graph->collections[0] = list_to_add;
// PRINT OUT THE VALUES OF THE NEWLY ADDED NODE TO MAKE SURE IT WORKS
// THE URL_NAME IS PRINTED OUT FINE
// BUT THE ID IS JIBBERISH.
printf("%s\n", new_graph->collections[0]->URL_NAME);
printf("%d\n", new_graph->collections[0]->id);
if(new_graph->collections[0]->next != NULL) {
printf("%s\n", new_graph->collections[0]->next->URL_NAME);
printf("%d\n", new_graph->collections[0]->next->id);
}
printf("\n");
return new_graph;
}
I expect new_graph->collections[0]->id to be 0 but it keeps on giving me random ints.
Also even if the next for the newly declared pointer to struct is NULL, it still gives me a jibberish next value too.
Any help would be appreciated, thanks!
The data member collections of the object *new_graph is not initialized.
There is initialized only this data member
new_graph->nV = size;
So this statement
new_graph->collections[0] = list_to_add;
results in undefined behavior.
If you need an array of pointers of the type URLList you have to allocate the memory and its address assign to the pointer collections.
For example
new_graph->collections = malloc( new_graph->nV * sizeof( URLList ) );
And after that this statement
new_graph->collections[0] = list_to_add;
could be valid.
(I suppose that the data member nV corresponds to the number of elements in the dynamically allocated array though it may not be truth)
Pay attention to that as the string pointed to by the pointer name is not changed in the function then it is better to declare it like
const char *name = getNextVal(s);

Creating array of pointers

I need to create an array to pointers of pNodes but when i declare it i dont know the length of the array
lets see what i mean
this is the Node struct
typedef struct _Node {
struct _Node* next;
pElement element;
} Node, *pNode;
this is the Hash struct
typedef struct _Hash {
int hashSize;
pNode *hashTable;
}Hash,*pHash;
now i want each of the
hashTable boxes to point to a pNode
the problem is that i dont know the size of the array, if i did it would be like (i guess)
pNode hashTable[hashSize]
the way i wrote it and tried to resett all boxes to NULL:
this is the CODE:
allocation memory:
pHash hash = (pHash)(malloc(sizeof(Hash)));
hash->hashTable = (pNode)(malloc(sizeof(pNode) * size));
hash->hashSize = size;
resetHashTable(hash->hashTable, size); // reseting the array to NULLS
the func:
static void resetHashTable(pNode *hashTable, int size) {
int i;
for (i = 0; i < size; i++) {
hashTable[i] = (pNode)NULL;
}
}
one of the many many errors i get from the program is (the first error)
hash.c:37:18: warning: assignment from incompatible pointer type [enabled by default]
hash->hashTable = (pNode)(malloc(sizeof(pNode) * size));
can i have some pointers how i need to write it?
If this is not C++ just don't cast malloc, you have an error in this line
hash->hashTable = (pNode)(malloc(sizeof(pNode) * size));
It could be
hash->hashTable = (pNode *)(malloc(sizeof(pNode) * size));
// ^ hashTable is declared pNode *
A better solution would be
hash->hashTable = malloc(sizeof(pNode) * size);
You are declared the pNode as a pointer. Then in Hash structure You are declared the pNode * hastable So you have to use the double pointer **. Or else make that as single pointer in hash structure.
hash->hashTable = (pNode*)(malloc(sizeof(pNode) * size));

warning in pointer assigning

I'm relatively new to C. And I wrote the following code:
#include "HashTable.h"
hashTable* newHashTable()
{
hashTable* h = malloc(sizeof(hashTable));
h -> size = TABLE_SIZE;
h -> table = createTable(TABLE_SIZE);
return h;
}
entry* createTable(int size)
{
entry* table = malloc(sizeof(entry) * size);
int i;
for(i=0; i<size; i++)
(table + i) -> word = NULL;
return table;
}
and the content of HashTable.h is:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define TABLE_SIZE 7
#define HASH_INCREMENT 3 // for efficient utilization of the hash table keep TABLE_SIZE * 2^n relative prime to HASH_INCREMENT
typedef struct entry_t
{
char* word;
int frequency;
}entry;
typedef struct hashTable_t
{
int size;
entry* table;
}hashTable;
When I try to compile this code (with some other code too) I get the following warning:
HashTable.c: In function ‘newHashTable’:
HashTable.c:7:13: warning: assignment makes pointer from integer without a cast [enabled by default]
Line 7 is actually the third line in newHashTable() function. I was looking at this for hours now. Please help me to resolve this warning.
Ansii C assumes that any function that is called without having been declared returns int.
You should either declare createTable before newHashTable
entry* createTable(int size);
hashTable* newHashTable()
{
/* implementation */
}
entry* createTable(int size)
{
/* implementation */
}
or move its implementation before any calls
entry* createTable(int size)
{
/* implementation */
}
hashTable* newHashTable()
{
/* implementation */
}
or declare the functions in the header that also defines the struct
typedef struct entry_t
{
char* word;
int frequency;
}entry;
typedef struct hashTable_t
{
int size;
entry* table;
}hashTable;
entry* createTable(int size);
hashTable* newHashTable();

Resources