I have an assignment about a labyrinth solving algorithm and I used a path tree to solve it, these are my structs:
typedef struct node* nodePtr;
typedef struct root{
int coordX;
int coordY;
nodePtr child[4];
} root;
typedef struct node{
int coordX;
int coordY;
char val;
nodePtr child[3];
void* parent;
} node;
The parent pointer can be either a pointer to root or a pointer to node to not to have a loop in tree. I checked this thing on assigning nodes:
void assignNode(nodePtr *nodeAddr, int x, int y, char **maze, void *parent){
...some codes...
if(y != parent->coordY && x != parent->coordX)
This is where I get annoying error of
dereferencing 'void *' pointer
error: request for member 'coordY' in something not struct or union
error: request for member 'coordX' in something not struct or union
You can't de-reference a void* like this. It needs to know the type of pointer (in your case either node* or root*). So, you need to typecast your pointer (either node* or root*). In this particular case, as node.
ie instead of
if(y != parent->coordY && x != parent->coordX)
write
if(y != ((node*)parent)->coordY && x != ((node*)parent)->coordX)
But since it your code, as you mentioned it could be either kind of the pointer (node* or root*), you need to have some way to identify it and then do the typecasting appropriately.
Related
This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 1 year ago.
I am trying to add a node to a binary search tree (BST). My adding method code is as follows:
int add(node_t* n, node_t* tn){
if(tn == NULL){tn = n;}
if(n->value < tn->value){add(n, tn->leftNode);}
else if (n->value > tn->value){add(n, tn->rightNode);}
else{return 0;}
return 1;
}
The method is called in main for BST t1 and node n1: add(n1, t1->root). The return value of the function is a 0 or 1, 0 if another node of the same value exists in the tree- in which case the new node is not added- and 1 if the node is successfully added. Struct tree_t's count variable is updated in the main function as follows: t1->count += add(n1, t1->root).
However, after I call the add function, the tree t1 still seems to be empty. My only guess is that add is adding a node to a copy of t1 which is being destroyed after the function call, but I don't understand why this is the case as it is passed in as a pointer.
The structs tree_t and node_t are attached below:
typedef struct node{
int value;
struct node* leftNode;
struct node* rightNode;
} node_t;
typedef struct tree{
struct node* root;
int count;
} tree_t;
And here is my main method:
int main(){
tree_t t1;
tree_init(&t1);
node_t n1;
node_init(&n1, 5);
node_t n2;
node_init(&n2, 7);
t1.count += add(&n1, t1.root);
t1.count += add(&n2, t1.root);
print_tree(t1.root); //this prints nothing, and I'm confident that print_tree works
}
Any help is greatly appreciated!
If you pass to function pointer to type, you can change the variable that pointer points to. But you can't change the address, that this pointer points to (can't change pointer itself).
If you want to change pointer itself (address that he points to), you need to pass in your function pointer to pointer:
int add(node_t *n, node_t **tn){
if(*tn == NULL){*tn = n;}
if(n->value < *tn->value){add(n, *tn->leftNode);}
else if (n->value > *tn->value){add(n, *tn->rightNode);}
else{return 0;}
return 1;
}
I've been learning C for a month now and I've learned/remember that functions are defined like this:
return_type function_name( parameter list ) {
...body
}
But in a lecture about 'list ADTs' the example code which illustrates making and printing a full list there were some pieces of code(function declarations) in a form that I've never seen.
...
typedef struct list{ int data; struct list *next; } list;
list* create_list(int d) {
...
}
To my understanding the return type is ' list '(?) which is a structure tag, and the function name is ' * create_list ' (which is a dereferenced pointer??). I couldn't understand why it was written like that. I want to know how it works and how to use it. How does it differ from other (normal looking)functions like struct create_list(int d) {...}? The instructor didn't mention or explain about these so I'm quite confused.
here is the full code just in case
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
typedef struct list{ int data; struct list *next;} list;
int is_empty(const list *l) { return (l == NULL); }
list* create_list(int d) {
list* head = malloc(sizeof(list));
head -> data = d;
head -> next = NULL;
return head;
}
list* add_to_front(int d, list* h) {
list* head = create_list(d);
head -> next = h;
return head;
}
list* array_to_list(int d[], int size) {
list* head = create_list(d[0]);
int i;
for(i = 1; i < size; i++) {
head = add_to_front(d[i], head);
}
return head;
}
void print_list(list *h, char *title) {
printf("%s\n", title);
while (h != NULL) {
printf ("%d :", h -> data);
h = h -> next;
}
}
int main() {
list list_of_int;
list* head = NULL;
int data[6] = {2,3,5,7,8,9};
head = array_to_list(data, 6);
print_list(head, "single element list");
printf("\n\n");
return 0;
}
any help would be appreciated!
Please correct me if I'm wrong in some point. Thank you
You're close, but reading it wrong. Function names do not have things like * in them, only types do.
This defines a function that returns list* (a.k.a. struct list* which is what typedef establishes earlier) given argument d of type int:
list* create_list(int d) {
// ...
}
In other words, create_list returns a pointer to list. In a type definition * means pointer, but it has a different meaning as an operator, such as:
int x = 0;
int* y = &x;
*y = 5; // Dereference y pointer, make assignment, in other words, assign to x
You can usually spot a dereference operator because it is not part of a type either in a return type specifier, an argument, or a variable declaration. In most other cases it's the dereference operator.
To my understanding the return type is ' list '(?) which is a structure tag
In your example list is both a struct tag and a typedef name. The name space rules of C allow four different categories of identifiers:
lables (for goto etc)
struct/union/enum tags (struct this_is_a_tag).
struct/union members
everything else
It's valid to name identifiers from these different name spaces the same.
In the example
typedef struct list{ int data; struct list *next;} list;
the typedef list identifier isn't available until at the end of the declaration (after the ;). The struct tag struct list is, however. So the struct list *next; member refers to the struct tag, which is a convenient way create a self-referencing struct. Once the typedef is declared, we can either use list to refer to the typedef:ed struct type, or we can use struct list which means the very same thing - when used outside the struct declaration it's just a style preference which form to use.
So list* create_list(int d) is using the typedef list to declare the return type of the function as a pointer to struct, list*. No different from returning any variable by value vs returning a pointer to it.
In this case the function is calling malloc to create a struct variable, so the function needs to return a pointer because anything allocated by malloc is always accessed through pointers.
I am trying to implement graph using adjacency list ,according to my knowledge that i have learnt so far if i created variable array pointer to struct adjlistnode of size v*sizeof(struct adjlistnode) thin i can store the addresses of v struct adjlistnode type node in each index of array
Means that each index of array will point to the node of type struct adjlistnode but when i am assigning G->array[i]=NULL it gives me error
||=== Build: Debug in teeest (compiler: GNU GCC Compiler) ===|
C:\Users\Mahi\Desktop\DATA STR\teeest\main.c||In function 'creategraph':|
C:\Users\Mahi\Desktop\DATA STR\teeest\main.c|59|error: incompatible types when assigning to type 'struct adjlistnode' from type 'void *'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
why i am not able to assign NULL to index of array
what should i do if i want to access adjacency list like using G->array[i]=first node address adjacent to ith vertex of graph and later i will add another node if needed
struct adjlistnode{
int dest;
struct adjlistnode* next;
};
struct graph{
int V;
struct adjlistnode* array;
};
struct adjlistnode* getnewnode(int dest){
struct adjlistnode* newnode =(struct adjlistnode*)malloc(sizeof(struct adjlistnode));
newnode->dest=dest;
newnode->next=NULL;
return newnode;
}
struct graph* creategraph(int v){
struct graph* G=(struct graph*)malloc(sizeof(struct graph));
G->V=v;
G->array=(struct adjlistnode*)malloc(v*sizeof(struct adjlistnode));
for(int i=0;i<v;i++){
G->array[i] =NULL;
}
return G;
}
G->array is of type struct adjlistnode *
But
G->array[i] is of type struct adjlistnode.
Thus you cannot assign NULL (of type void *) to G->array[i] of type struct adjlistnode
You should probably have to define array in the struct graph as pointer to pointer
struct graph{
int V;
struct adjlistnode** array;
};
and then the following should work for you
struct graph* creategraph(int v){
struct graph* G=malloc(sizeof(struct graph));
G->V=v;
G->array=malloc(v*sizeof(struct adjlistnode*));
for(int i=0;i<v;i++){
G->array[i] =NULL;
}
return G;
}
** Note1 (as also mentioned by #alk in the comments) that in C, at least since C89 standard, malloc returns void *. void * can be assigned to any other pointer type (and visa versa), thus casting the return value of malloc is not required.
** Note2 (also noted by #alk) that malloc signature is defined with the parameter of type size_t and not int so better to modify the code a little and use the proper type ( Read comparing int with size_t and size_t vs int in C++ and/or C for more info)
array is a (single) pointer to struct adjlistnode. So it can be set to NULL.
G->array = NULL; //is okay
But it is not an array of pointers, so you cannot access the elements of the array and they cannot be set to NULL as well.
For dynamic allocation, you should do this:
struct graph{
int V;
struct adjlistnode** array;
};
struct graph* creategraph(int v){
struct graph* G = malloc(sizeof(struct graph));
G->V = v;
G->array = malloc(v * sizeof(struct adjlistnode*)); //allocation for an array of v pointers
for(int i = 0; i < v; i++){
G->array[i] = NULL;
}
return G;
}
As suggested by #alk, it is better if you pass v as size_t instead of int, as malloc takes size_t.
G->array[i] returns *(array + i * sizeof(struct adjlistnode)) as if array was struct adjlistnode array[].
What you do is store v objects of struct, but you try to initialize them with NULL, like you would a pointer.
What you probably want is
struct graph{
int V;
struct adjlistnode** array;
};
[...]
G->array=(struct adjlistnode**)malloc(v*sizeof(struct adjlistnode*));
That would make array a pointer to an array of pointers.
Then G->array[i] would return a struct adjlistnode* pointer to an object of struct, that you can then initialize with your getnewnode().
I am creating a code to insert the elements in tree, but tinsert function does not insert; what is wrong with my code? I have checked many times but tree is always NULL.
The code has only 2 functions: one to insert, and second to show it in preorder.
#include<stdio.h>
#include<stdlib.h>
struct btree {
int val;
struct btree *left;
struct btree *right;
};
static int c=0;
typedef struct btree node;
void tinsert( node *n,int a)
{
c++;
printf("%d\n",c);
if(n==NULL)
{
n=(node *)malloc(sizeof(node));
n->left=NULL;
n->right=NULL;
n->val=a;
//printf("adding root %d\n",n->val);
//n=temp;
}
else if(a>=(n->val))
tinsert(n->right,a);
else
tinsert(n->left,a);
return ;
}
void preorder_display(node *n)
{
if(n!=NULL)
{
printf("%d\n",n->val);
preorder_display(n->left);
preorder_display(n->right);
}
else
printf("tree is null\n");
}
int main()
{
//int N;
//int num[100];
//int i;
node *ntree=NULL;
tinsert(ntree,4);
tinsert(ntree,6);
tinsert(ntree,8);
tinsert(ntree,1);
printf("tree is \n");
preorder_display(ntree);
return 0;
}
tinsert works on a local copy of your ntree, it doesn't change the one in your main. You can fix it by passing a pointer to it (i.e.: double pointer, pointer to a pointer).
So your tinsert will look like this:
void tinsert( node **n,int a)
And in your main you'll call it like this:
tinsert(&ntree,4);
Of course, you'll need to adjust the code in tinsert to de-reference the pointer and access it correctly.
Or allocate the root node in your main.
you pass your root node ntree to tinsert function by value, so when when the function is done you will stay with original value of ntree which is NULL.
You better rewrite your function, so you will pass pointer to pointer
void tinsert( node **n,int a)
//and invocation is like that :
tinsert(&ntree,4);
when you pass ntree from main to tinsert function,
new copy is created to your node*n;
One way is to make use of pointer to pointer
Or second solution is here:
Here is a solution:
#include<stdio.h>
#include<stdlib.h>
struct btree{
int val;
struct btree *left;
struct btree *right;
};
static int c=0;
typedef struct btree node;
node* tinsert( node *n,int a)
{
c++;
printf("%d\n",c);
if(n==NULL)
{
n=(node *)malloc(sizeof(node));
n->left=NULL;
n->right=NULL;
n->val=a;
//printf("adding root %d\n",n->val);
//n=temp;
}
else if(a>=(n->val))
tinsert(n->right,a);
else
tinsert(n->left,a);
return n;
}
void preorder_display(node *n)
{
if(n!=NULL)
{
printf("%d\n",n->val);
preorder_display(n->left);
preorder_display(n->right);
}
else
printf("tree is null\n");
}
int main()
{
//int N;
//int num[100];
//int i;
node *ntree=NULL;
ntree=tinsert(ntree,4);
ntree=tinsert(ntree,6);
ntree=tinsert(ntree,8);
ntree=tinsert(ntree,1);
printf("tree is \n");
preorder_display(ntree);
return 0;
}
C supports the pass by value only. However, this does not prevent you from modifying the value of a variable from another function, because you can always refer to a variable using it's memory; and in C it's done through pointers, an abstraction representing a memory location.
When you pass a value to the function, the value of the actual parameter is copied to the value of formal parameter. Note that a pointer's value is the address it points to. So, this value is copied into the formal parameter. So the new pointer inside the function points to the exact same location your original variable. You can deference the pointer anytime to manipulate it's value.
Here, you are required to manipulate a pointer. So you pass a pointer-to-pointer to the function:
tinsert(&ntree,4);
In your function, you deference it to get your original pointer; like the following:
void tinsert(node **n, int a)
{
//...
*n = malloc(sizeof(node));
//...
}
I'm trying to save the address of a dynamic array index. The last line of this function is what gives the pointer error.
static struct sstor *dlist
struct node *ins_llist(char *data, struct llist *l) {
struct node *p, *q;
q = malloc((size_t)sizeof(struct node));
if(q == NULL)
return(NULL);
if(ins_list(data, &dlist))
return NULL;
q->item = &(dlist->item[(dlist->sz)-1]); // Problem?
...}
Allocation of dlist
struct llist *init_llist(void) {
struct llist *l;
dlist = init_list(INITSZ);
if(dlist == NULL)
return(NULL);
This is my node
struct node {
char **item;
struct node *next;
struct node *prev;
};
This is my array
struct sstor {
int sz;
int maxsz;
char item[][1024];
};
I'm still new to pointers. The line below gives the error: assignment from incompatible pointer type
q->item = &(dlist->item[(dlist->sz)-1]);
Presuming that you allocate an actual struct node for q to point to...
The "incompatible pointer types" error arises because q->item has type char ** (a pointer to a pointer to char), and &(dlist->item[...]) has type char (*)[1024] (a pointer to an array of 1024 char). These types simply aren't compatible (there is no actual "pointer to char" object for q->item to point to).
You can fix the problem in two ways. The first is by changing the declaration of struct node to this:
struct node {
char (*item)[1024];
struct node *next;
struct node *prev;
};
The second is by changing both the declaration of struct node to this:
struct node {
char *item;
struct node *next;
struct node *prev;
};
..and changing the assignment statement to this:
q->item = dlist->item[(dlist->sz)-1]; // No Problem!
(The first alternative makes q->item point to the entire array, and the second makes it point to the first char in the array. The perspecacious will note that these are pointers to the same location, but with different types. Usually, the second form is what you want).
char** is not the same as char[][1024]
Try to fix the sstor structure like this:
struct sstor {
int sz;
int maxsz;
char *item[1024];
};