0

I am new to C and as a (classic) exercise I am trying to implement some operations on linked lists. I haven't gotten very far yet, though... When I am trying to declare and initialize the root node as follows:

#include <stdlib.h>

struct intNode_t {
    int data;
    struct intNode_t* next;
};

int main() {
    struct intNode_t* root = ( intNode_t* ) malloc( sizeof( struct intNode_t ) );
    return 0;
}

the compiler (clang) is giving me the error "use of undeclared identifier" at the place where I am trying to typecast the void pointer returned by malloc to a pointer to intNode_t. I realise this is a noob question, but I couldn't find the answer elsewhere. Any suggestions?

NiH
  • 434
  • 6
  • 16
  • You've spelled the typename `struct intNode_t` twice in your main function. Why are you surprised that the differently spelled name `intNode_t` behaves differently? – Kerrek SB Mar 28 '16 at 13:57
  • 1
    NOTE: `struct intNode_t*` and `intNode_t*` is not the same thing. At least not in C. Just remove that type cast and you will make a lot of people (including yourself) happy. – tofro Mar 28 '16 at 13:57
  • 1
    Who told you that you should cast the result of `malloc`? Please stop listening to that person immediately, as they will be a major obstacle on your road to learn C. – Kerrek SB Mar 28 '16 at 13:58
  • 1
    You forget the semicolon after struct and before main – David Ranieri Mar 28 '16 at 13:58
  • @AlterMann : that was a typo in the question, not in my actual code. Corrected it. Thanks! – NiH Mar 28 '16 at 14:08
  • thanks for all the comments. @KerrekSB I was told that malloc returns a void pointer and I need a pointer to type intNode_t . why is that bad/wrong? – NiH Mar 28 '16 at 14:10
  • 1
    @NiH: Because there is an implicit conversion from void pointer to any object pointer. See my answer. It's very dangerous to "be told" stuff, because 90% of programmers are bad programmers, so by randomly listening you have a high chance of copying someone bad. – Kerrek SB Mar 28 '16 at 14:12

3 Answers3

4

The names of structs in C occupy a separate namespace from the space of names of fundamental types and typedefs (see this question for details). Therefore, the name of your struct type is struct intNode_t; there is no type called intNode_t.

You can either always spell out the name as struct intNode_t, or you can create a type alias for it. There are many different patterns of this in real code:

Separate tag name, separate declaration:

typedef struct foo_t_ foo_t;

struct foo_t_ { /* ... */ };

This allows you to put the type alias in a header and publish it as an opaque API type without ever revealing the actual type definition.

Separate tag name, typedef in struct definition:

typedef struct foo_t_ { /* ... */ } foo_t;

Reuse name:

typedef struct foo_t { /* ... */ } foo_t;

This style allows users to be careless about spelling foo_t or struct foo_t.

Don't name the struct:

typedef struct { /* ... */ } foo_t;

However, in your code you don't actually need to repeat the name, since you should not cast the result of malloc and instead rely on the built-in implicit conversion from void pointer to object pointer. You also shouldn't repeat the type that's already known, and use the expression form of sizeof instead. So you want:

int main()
{
    struct intNode_t* root = malloc(sizeof *root);
}

(Also note that return 0 is implied from main.)

Community
  • 1
  • 1
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

No need to repeat yourself. If you don't repeat yourself you can make fewer errors.

struct intNode_t *root;
root = malloc( sizeof *root );
  • the cast is not needed; malloc() returns a void*, which is exchangeable with every (non-function) pointer type.
  • there are two syntax variants for sizeof: sizeof(type) and sizeof expression The first one needs (), the second one does not. Most people prefer the second form, because the expression (in your case *root ) always will yield the correct type, and thus: size.

And, the definition + assignment above can be combined into a definition + initialiser, all fitting on one line:

struct intNode_t *root = malloc( sizeof *root );
wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • Why have a separate declaration and assignment? That just adds noise and removes locality. – Kerrek SB Mar 28 '16 at 14:19
  • 1
    Oops. corrected. 2) because beginners often are confused by the different role of the `*` in declarations/definitions and expressions/initialisers. – wildplasser Mar 28 '16 at 14:21
0

Name intNode_t was not declared in the program. There is declared structure tag name intNode_t.

So you need to write

struct intNode_t* root = ( struct intNode_t* ) malloc( sizeof( struct intNode_t ) );

Or you could introduce identifier name intNode_t the following way

typedef struct intNode_t {
    int data;
    struct intNode_t* next;
} intNode_t;

In this case you may write

struct intNode_t* root = ( intNode_t* ) malloc( sizeof( struct intNode_t ) );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335