Let's analyse your code a bit:
typedef struct nodes
{
int data;
struct node *next;
}node;
This declares and defines struct nodes, a type with two members, and declares a type alias so we can refer to it only as node.
Now, in C++, the member declaration struct node *next automatically forward-declares a type called node. That then conflicts with your typedef target node: it's as if you're trying to give two types the same name.
In C, there is no conflict, because the type called node can in fact only be referred to as struct node.
The second snippet worked because, since during parsing of the member declaration struct node already exists, no new type is forward-declared there … and since all you're then doing is renaming it in the same typedef statement, C++ doesn't really care, knowing that it's all the same type (struct T is T; the difference is in syntax, not in name).
[C++11: 7.1.3/3]: In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. [ Example:
typedef struct s { / ... / } s;
typedef int I;
typedef int I;
typedef I I;
—end example ]
[C++11: 7.1.3/6]: In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type. [ Example:
class complex { / ... / };
typedef int complex; // error: redefinition
—end example ]
Of course, in C++, this is all moot and you should just write:
struct node
{
int data;
node* next;
};
You do not need to typedef-away the elaborated-type-specifier struct.