Creating array of pointers - c

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));

Related

Casting pointers to void to pointers to pointers to type A and dereferencing vs. Casting pointers to void to type A: Why?

I am just starting to learn C. Any help is appreciated!
I have an array of pointers to a struct, and I want to use the built-in qsort function to sort the array according to values in the structs the pointers point to. I am trying to use a compare function as demonstrated in the official docs.
The following version fails:
int compare_nodes(const void* a, const void* b){
const struct ListNode * ptr1 = ((const struct ListNode *) a);
const struct ListNode * ptr2 = ((const struct ListNode *) b);
// const struct ListNode * ptr1 = *((const struct ListNode **) a);
// const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
This version succeeds:
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
I do not understand the difference between the two versions:
If casting only tells the compiler how to interpret the address the pointer points to, what is the problem in version 1? Is it not enough to tell the compiler to interpret the pointer to void as a pointer to struct ListNode? Why do I need to add a layer of indirection with casting, just to then remove one layer with dereferencing?
Does C's pass-by-value play any role here? I could not think of any reason why by myself.
I found the following resources about this question. Although they seemed to explain this problem (especially resource 6), I did not understand them:
What are the rules for casting pointers in C?
Typecasting of pointers in C
Pointer type casting and dereferencing
What are the rules for casting pointers in C?
What does a C cast really do?
https://cboard.cprogramming.com/c-programming/102056-casting-pointer-pointer.html
Here's the full code:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
struct ListNode {
int val;
struct ListNode *next;
};
int calc_list_length(struct ListNode * head){
int target = 0;
struct ListNode * tmp = head;
while (tmp)
{
target++;
tmp = tmp -> next;
}
return target;
}
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
struct ListNode* sortList(struct ListNode* head){
if(!head) return NULL;
int list_length = calc_list_length(head);
struct ListNode * tmp = head;
struct ListNode * arr[list_length];
for (int i = 0; i < list_length; i++)
{
arr[i] = tmp;
tmp = tmp -> next;
}
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
qsort(arr, list_length, sizeof(struct ListNode *), compare_nodes);
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
}
int main(){
// [2,1,4,3]
struct ListNode node4 = {.val = 3, . next = NULL};
struct ListNode * ptr4 = &node4;
struct ListNode node3 = {.val = 4, .next = ptr4};
struct ListNode * ptr3 = &node3;
struct ListNode node2 = {.val = 1, .next = ptr3};
struct ListNode * ptr2 = &node2;
struct ListNode node1 = {.val = 2, .next = ptr2};
struct ListNode * ptr1 = &node1;
sortList(ptr1);
getchar();
return 0;
}
Thanks in advance. I hope you point me in the right direction.
The qsort passes pointers to the array elements using the pointer-to operator &.
So it can pass, for example, &arr[0] and &arr[1] as arguments to your comparison function.
Since arr is an array of pointers, where every element is a pointer, then a pointer to one element must by definition be a pointer to a pointer.
So the arguments passed to your compare_nodes structure are pointers to pointers to ListNode structures.
The function qsort is declared like
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
That is the function deals with pointers of the type void *. It passes to the comparison function two pointers of the type const void * that point to elements of the underlying array.
You declared an array of pointers
struct ListNode * arr[list_length];
Its elements of the type ListNode * are passed to the comparison function by reference through pointers to them.
In fact the function passes to the comparison function pointers of the type
ListNode ** that are passed as pointers of the type const void *. You may imagine this the following way
const void *p = &arr[i];
where the expression &arr[i] has the type ListNode **.
Of course the function qsort actually does not know the actual type of elements of the array. It uses the following pointer arithmetic
const void *p = ( char * )base + i * size;
Thus within the comparison function you need to do the "reverse" casting like
const struct ListNode * ptr1 = *((const struct ListNode **) a);
where ptr1 is an element of the original array that is passed to the comparison function by reference trough a pointer to it..
The fact that the qsort() function passes pointers to the array elements to your comparator function, rather than passing the array elements directly by value, is due to how qsort() was designed, and is not required by the core C language itself.
I can easily write a sorting function that sorts an array of pointers, with the following signature:
void my_sort_pointers(const void **array, size_t nmemb,
int (*compar)(const void *, const void *));
and it accepts a comparator function that is passed the array elements (the pointers) directly. Then your comparator function would not have to dereference the argument to get the actual values to be compared.
However, my sorting function above would not be able to sort, say, an array of floats, because it would not be able to pass two float arguments to a comparator function that is supposed to take two pointers. Even if you made a comparator function that took two floats, you would not be able to pass it to the function above, because the function pointer types are incompatible, and even if you somehow casted the type, it would still not work because the C code inside the function, which thinks it is calling a function that takes two pointers, cannot call a function that actually takes two floats, because the function signatures are incompatible.
So to be able to sort arrays of different types under this design, I would have to have another sorting function that sorts an array of floats:
void my_sort_floats(float *base, size_t nmemb,
int (*compar)(float, float));
and another sorting function that sorts an array of ints, etc. And since there can be an unlimited types of structs, with different sizes, you can never make functions that can handle all of them. Even if only basic types are supported, it would require several different functions. The designers of the C standard library decided that it would be a better design to make a single sorting function that works for all types, by passing a pointer to the array element to the comparator functon instead.
This design makes a lot of sense when you understand the limitations of C. (In C++, it would be possible to use generics to write a generic sorting function that works for any type, and has a comparator that is passed the array elements by value. But C doesn't have generics.) But it is a design decision of the qsort() function API nevertheless, and sorting functions in C (at least if they only accept a particular type) do not necessarily have to work this way. So you would only know that qsort() is supposed to be used in this way by reading the specification of qsort().

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;

Initializing C struct using pointer to pointer

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);
}

How to initialize an void* pointer from struct

I have a struct Element. When I try to initialize the elements array to NULL,
I get the error: incompatible types when assigning to type Element from type void *.
How to initialize the void * array?
typedef struct _Element Element;
struct _Element {
void* data;
};
typedef struct _ArrayList ArrayList;
struct _ArrayList {
int size;
Element *elements;
};
int main() {
ArrayList *list;
list->size = 100;
list->elements = (Element*)calloc(sizeof(Element), list->size);
for (i = 0; i < list->size; i++) {
/*
* error: incompatible types when assigning to type
* ‘Element’ from type ‘void *’
*/
list->elements[i] = NULL;
}
}
Firstly, you never allocated memory for your list object! Your list pointer is uninitialized and points nowhere. Trying to apply the -> operator to it causes undefined behavior.
I don't know what your final intent is, but it should be either something like
ArrayList *list = malloc(sizeof *list);
list->size = 100;
...
or
ArrayList list;
list.size = 100;
...
Secondly, your void * pointer is actually a named field called data inside Element struct
for(i = 0; i < list->size; i++)
list->elements[i].data = NULL;
Thirdly, becuse you used calloc the memory is already sort of "initialized" with all-zero bit-pattern (including your data fileds). Formally, such bit-pattern in void * is not guaranteed to represent a null pointer, but on most platforms it actually does.
P.S. Don't cast the result of calloc
list->elements = calloc(sizeof(Element), list->size);
or event better
list->elements = calloc(sizeof *list->elements, list->size);
Apart from all the logical errors, the compiler error is the result of trying to assign a value (NULL) to a struct-typed variable. The fact that the struct contains a void * is coincidental. You'd get the same error with:
typedef struct _Element Element;
struct _Element{
int data;
};
Element e;
e = NULL;
This is most likely a mistake from what you intended to do, which is assign a value to the variable inside the struct:
for(i = 0; i < list->size; i++)
list->elements[i].data = NULL;

function argument a pointer array (C)

in my code I have a array of pointers, where the pointers point to my struct
struct Container *bucket[sizeOfHashMap];
I have a function that will return 1 of these array pointers (e.g it may return the pointer at array index 6). As an argument it wants a pointer to this pointer. The function can be seen here:
struct Container* getWhichBucket(char word[], struct Container **bucket[10]){
int value = 0;
int i = 0;
int size = strlen(word);
int hashIndex = 0;
for(i =0; i < size; i++){
value += (int)word[i];
}
//size of array is worked out by getting memory that array takes up / a slot
hashIndex = value % sizeOfHashMap;
return *bucket[hashIndex];
}
I call the function like this (where test is an array of characters)
addToBucket(test, getWhichBucket(test, &bucket));
the add to bucket looks like this:
void addToBucket(char word[], container **bucket){
container *temp = (struct Container*)malloc (sizeof(struct Container));
strcpy(temp->key, word);
temp->value = 9001;
temp->next = *bucket;
*bucket = temp;
return;
}
However the compiler issues warnings when I compile the code and when I run it I get a segmentation error. Does anyone know why? The warnings can be seen here:
cw.c: In function ‘main’:
cw.c:86:2: warning: passing argument 2 of ‘getWhichBucket’ from incompatible pointer type [enabled by default]
cw.c:37:19: note: expected ‘struct Container ***’ but argument is of type ‘struct Container * (*)[(long unsigned int)(sizeOfHashMap)]’
cw.c:86:2: warning: passing argument 2 of ‘addToBucket’ from incompatible pointer type [enabled by default]
cw.c:56:6: note: expected ‘struct container **’ but argument is of type ‘struct Container *’
addToBucket(test, getWhichBucket(test, &bucket));
is passing a
struct Container *(*)[10]
to getWhichBucket. That's the wrong type, as the compiler says.
You can fix the prototype and implementation
struct Container* getWhichBucket(char word[], struct Container *(*bucket)[10]){
int value = 0;
int i = 0;
int size = strlen(word);
int hashIndex = 0;
for(i =0; i < size; i++){
value += (int)word[i];
}
//size of array is worked out by getting memory that array takes up / a slot
hashIndex = value % sizeOfHashMap;
return (*bucket)[hashIndex];
}
or change the call, but there's no easy way to get a struct Container **bucket[10] from a struct Container *bucket[10], so then you'd probably still want to change the type and implementation of getWhichBucket.
Since you're not modifying the bucket argument there, there's no need to pass the address, you can simply pass the struct Container *bucket[10] directly,
struct Container* getWhichBucket(char word[], struct Container *bucket[]){
int value = 0;
int i = 0;
int size = strlen(word);
int hashIndex = 0;
for(i =0; i < size; i++){
value += (int)word[i];
}
//size of array is worked out by getting memory that array takes up / a slot
hashIndex = value % sizeOfHashMap;
return bucket[hashIndex];
}
and call
addToBucket(test, getWhichBucket(test, bucket));
You need to change your declaration of addToBucket from
void addToBucket(char word[], container *bucket)
{
container *temp = (struct Container)malloc (sizeof(struct Container));
strcpy(temp->key, word);
temp->value = 9001;
temp->next = *bucket;
*bucket = temp;
return;
}
to
void addToBucket(char word[], Container *bucket)
{
Container *temp = malloc (sizeof(struct Container));
strcpy(temp->key, word);
temp->value = 9001;
temp->next = *bucket;
*bucket = temp;
return;
}
Note the change in case for Container -- case matters in C... container is not the same thing as Container.
Also... note... you should not cast malloc in C.

Resources