0

I need to figure out how to pass two different structs to a function. I tried using void * for the parameter but i am receiving the error:

warning: dereferencing 'void *' pointer
error: request for member left in something not a structure or union

same error for member right

here is what i did in general terms(code may not compile).

struct A{
    char *a;
    struct A *left, *right;
} *rootA;

struct B{
    char *b;
    struct B *left, *right;
} *rootB;

void BinaryTree(void *root, void *s){
    if(condition)
        root->left=s;
    else if(condition)
        BinaryTree(root->left, s);

    if(condition)
        root->right=s;
    else if(condition)
        BinaryTree(root->right, s);
}

int main(){
    // Assume the struct of nodeA and nodeB get malloc() 
    // as well as the variables a and b with actual data.
    struct A nodeA;
    struct B nodeB;
    BinaryTree(rootA, nodeA);
    BinaryTree(rootB, nodeB);

    return 0
}
Kninnug
  • 7,992
  • 1
  • 30
  • 42
user2644819
  • 1,787
  • 7
  • 28
  • 41
  • 2
    Your code indicates that you aren't passing pointers. Did you mean `BinaryTree(rootA, &nodeA)` etc? – lurker Nov 27 '13 at 00:11
  • I am passing the memory location of nodeA and nodeB. The void pointer in the parameter of the function should dereference it for use in the function no? – user2644819 Nov 27 '13 at 00:14
  • Your parameter type is pointer. You're passing the whole struct, not the pointer to the struct. Although there may be issues beyond that as well. The compiler will not "dereference" a struct to a void pointer. – lurker Nov 27 '13 at 00:15
  • dereferencing of the `void *` pointer occurs in function `BinaryTree` when you assume `root` is some struct containing `left`. Since both `struct A` and `struct B` are the same, refactor and cast the `void *` parameter into a pointer to your struct.. – amdixon Nov 27 '13 at 00:16
  • I'm referring to the `nodeA` paremeter. Also, inside the function, the first parameter is known to the function as a `void *` so it won't know what `root->left` is, for example. You'd need to do something like, `((struct A *)root)->left` which means you're going to need to know which struct `root` pertains to. – lurker Nov 27 '13 at 00:19

2 Answers2

0

There are 2 aspects of your program which needs to be relooked. One, is the parameter passing where you are passing by value and not reference. Hence, the calls for BinaryTree function should have

BinaryTree(rootA, &nodeA);

The other major consideration is how you handle these void pointers in the BinaryTree function. In the current form,

void BinaryTree(void *root, void *s){
    if(condition)
         root->left=s;

Here root is a void * and hence, root->left can't be evaluated. Hence, you need to typecast root to a meaningful data type like

struct A *hdl = (struct A*)(root);
hdl->left = s;

Even with this approach, one more important consideration is that you are using the same function for different structures. Hence, it would be difficult/challenging to know when to type cast root as A vs B and hence, this strategy requires a small rethink.

Ganesh
  • 5,880
  • 2
  • 36
  • 54
  • 1
    With the assignment a cast is not necessary since `void *` will automatically be promoted. If `root` were used without assigning it to a usable data-type it would have to be cast before accessing a member. – Kninnug Nov 27 '13 at 00:20
  • @Kninnug... Yes, I agree. I kept it for readability sakes and to highlight the point that the `void *` should be converted into a more meaningful data type pointer. – Ganesh Nov 27 '13 at 00:21
0

You are confused on your struct declarations. The type is given by the word after struct. That thing at the end needs to go, at least until you learn about typedefs. Example:

struct A{
char *a;
struct A *left, *right;
};

When you call BinaryTree you need to always pass it pointers not structs. Example:

BinaryTree(&nodeA, &nodeA);

When you do operations on a void pointer, you need to cast it to the correct pointer type first. Example:

(struct A*)root->left=s;

Passing these structs around as void pointers is definitely bad practice and you will get yourself horribly confused. Void pointers are to be used sparingly. Since you seem to be starting on C, I recommend you don't use them at all yet until you understand value and reference semantics a little better. That being said, I made lots of stupid code when I started on C, still do sometimes. You'll figure it out with time and practice.

Void Star
  • 2,401
  • 4
  • 32
  • 57
  • The thing at the end simply declares a variable of the defined `struct`, i.e. `struct A{ ... } * rootA;` defines `struct A` and declares a variable `rootA` as a pointer to a `struct A`. Only when it is used in conjunction with `typedef` does it define `rootA` as a type. Your usage of `nodeA` as both arguments implies that you want to use `nodeA` as both the root and a node, which is probably not the OP's intention. Also as `struct A` was not `typedef`ed the cast to `(A*)` is not valid. – Kninnug Nov 27 '13 at 00:26
  • True, but I have a feeling that OP may not be using it as such. Why else would they have both local and global instances of these structs in these circumstances? – Void Star Nov 27 '13 at 00:28
  • 1
    Declaring the root of a tree global (but not the nodes) is not that strange. And you seem to imply that he wants to use `nodeA` as both root and node. Though the OP should watch out that `nodeA` and `nodeB` are now allocated on the stack and may run out of scope while they're still in the tree. – Kninnug Nov 27 '13 at 00:32
  • In most cases yes, but this is the main method, so the program will end when its scope runs out. A bad way to deal with persistent elements to be sure, but it works, haha. – Void Star Nov 27 '13 at 00:36