3

It's amazing how even the littlest program can cause so much trouble in C.

#include <stdio.h> 
#include <stdlib.h> 

typedef struct node {
    int value;
    struct node *leftChild;
    struct node *rightChild;
} node;

typedef struct tree {
    int numNodes;
    struct node** nodes;
} tree;

tree *initTree() {
    tree* tree = (tree*) malloc(sizeof(tree));
    node *node = (node*) malloc(sizeof(node));
    tree->nodes[0] = node;
    return tree;
}

int main() {
    return 0;
}

The compiler says:

main.c: In function 'initTree':
main.c:17: error: expected expression before ')' token 
main.c:18: error: expected expression before ')' token

Can you please help?

1
  • 4
    The cause of the error (name clashes) are not because of C. You'd get an error in many languages. (But yes, the error message is incomprehensible.) Commented Jan 22, 2011 at 15:20

8 Answers 8

14

You're using two variables named tree and node, but you also have structs typedefed as tree and node.

Change your variable names:

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int value;
    struct node *leftChild;
    struct node *rightChild;
} node;

typedef struct tree {
    int numNodes;
    struct node** nodes;
} tree;

tree *initTree() {
   /* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
   tree* atree = malloc(sizeof(tree)); /* different names for variables */
   node* anode = malloc(sizeof(node));
   atree->nodes[0] = anode;
   return atree;
}

int main() {
    return 0;
}
Sign up to request clarification or add additional context in comments.

3 Comments

So should I never try to cast a void returned from malloc?
@sombe - you don't have to (in C), the conversion from void * to your pointer type is implicit.
@sombe, yes. If you do, you might hide some implicit casts to int if the prototype of malloc is not included.
5

tree and node is your case are type names and should not be used as variable names later on.

tree *initTree() {
    tree *myTree = (tree*) malloc(sizeof(tree));
    node *myNode = (node*) malloc(sizeof(node));
    myTree->nodes[0] = myNode;
    return myTree;
}

Comments

3

Change (tree*) and (node*) to (struct tree*) and (struct node*). You can't just say tree because that's also a variable.

7 Comments

Not necessary (typedef struct tree {} tree).
I tried it now, and it seems to compile. However, it works without struct (but only when the variable has a name not clashing with the type name).
@delnan: Exactly my point... hence why he needs to say struct if he doesn't change the rest of his code.
If he doesn't change the rest of the code, yes. But the majority (look at the votes) seems to think that renaming the variables is the real solution (it also allows dropping the arguably unnecessary struct before the typename).
But if there is a better solution, why not propose the better solution (and perhaps mention inferior ones)?
|
2

Change the body of initTree as follows:

tree* myTree = (tree *)malloc(sizeof(tree));
node *myNode = (node *)malloc(sizeof(node));
myTree->nodes[0] = myNode;
return myTree;

Comments

1

Don't use typedef'ed names as variable names, and there is not need to cast malloc(); in C.

#include <stdio.h> 
#include <stdlib.h> 

typedef struct node {
    int value;
    struct node *leftChild;
    struct node *rightChild;
} node;

typedef struct tree {
    int numNodes;
    struct node** nodes;
} tree;

tree *initTree() {
    tree->nodes[0] = malloc(sizeof(node));
    return malloc(sizeof(tree));
}

int main() {
    return 0;
}

Comments

0

I second that Mehrdad's explanation is to the point.

It's not uncommon that in C code you define a variable with the same name as the struct name for instance "node node;". Maybe it is not a good style; it is common in, e.g. linux kernel, code.

The real problem in the original code is that the compiler doesn't know how to interpret "tree" in "(tree*) malloc". According to the compiling error, it is obviously interpreted as a variable.

Comments

0

Apart from the original question, this code, even in it's correct forms will not work, simply due to the fact that tree::nodes (sorry for the C++ notation) as a pointer to a pointer will not point to anything usefull right after a tree as been malloced. So tree->nodes[0] which in the case of ordinary pointers is essentially the same like *(tree->nodes), can't be dereferenced. This is a very strange head for a tree anyway, but you should at least allocate a single node* to initialize that pointer to pointer:

tree *initTree() {
   /* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
   tree* atree = malloc(sizeof(struct tree)); /* different names for variables */

   /* ... */

   /* allocate space for numNodes node*, yet numNodes needs to be set to something beforehand */
   atree->nodes = malloc(sizeof(struct node*) * atree->numNodes);

   node* anode = malloc(sizeof(struct node));
   atree->nodes[0] = anode;
   return atree;
}

Comments

0

Interestingly, it does compile cleanly if you simply write the allocations as:

tree *tree = malloc( sizeof *tree );

It is often considered better style to use "sizeof variable" rather than "sizeof( type )", and in this case the stylistic convention resolves the syntax error. Personally, I think this example is a good case demonstrating why typecasts are generally a bad idea, as the code is much less obfuscated if written:

struct tree *tree = malloc( sizeof *tree );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.