struct key new_node = (struct key) calloc(1, sizeof(struct key));
calloc returns the value of the pointer ( void * ) that you are trying to convert and assign to the aggregated (IOW, non-scalar) type ( struct key ). To fix this, change the new_node type to struct key * and rewrite the selection as follows:
struct key *new_node = calloc(1, sizeof *new_node);
Two things to note. First of all, drop the expression. malloc , calloc and realloc all return void * , which can be assigned to any type of object pointer without the need for casting 1 . In fact, the presence of a cast can potentially mask the error if you forget to include stdlib.h or otherwise do not have an declaration for malloc in area 2 .
Secondly, note that I am using the *new_node expression as an argument to sizeof , not a (struct key) . sizeof does not evaluate its operator (unless it is a variable array type, which is not the case); it just calculates the type of expression. Since the type of the expression *new_node is equal to the struct key , sizeof will return the correct number of bytes to store this object. This can save some maintenance headaches if your code is structured as
T *foo; ...
and you change the type foo in the declaration, but forget to update the call to malloc .
Also, it is not clear what you are trying to accomplish using the typedefs and struct definitions. The code
typedef struct value_t value; struct value{ void* x; int y; value* next; value* prev; };
Don't do what you think. You create a name of typedef value , which is a synonym for type as-yet-undefined struct value_t . This value type is different from the struct value type that you create later (typedef names and struct tags live in different namespaces). Rewrite your structures to follow this model:
struct value_t { void *x; int y; struct value_t *next; struct value_t *prev; }; typedef struct value_t value;
In addition, life will be easier if you write your declarations so that * is associated with the declaration, and not a type 3 specifier. A declaration of type T* p parsed as if it were written by T (*p) . This will save you the embarrassment of writing int* a, b; and expects both a and b be pointers ( b is just a regular int ).
1 is one area where C and C ++ are different; C ++ does not allow implicit conversions between
void * and other types of object pointers, so if you compile this as C ++ code, you will get an error message during compilation. In addition, prior to the adoption of the 1989 standard,
*alloc functions returned
char * , so in those days the cast was necessary if you assigned a different type of pointer. This should be a problem if you are working with a very old system.
2 - Before the standard 1999, if the compiler saw a function call without a previous declaration, it assumed that the function returned int (so you still sometimes see examples like
main() { ... }
in some textbooks; main implicitly printed to return int . Starting with C99, this is no longer permitted). Therefore, if you forget to include stdlib.h and call calloc (and you do not compile like C99), the compiler will assume that the function returns int and will generate machine code accordingly. If you leave the cast, the compiler issues a diagnostic that you are trying to assign an int value to the pointer, which is not valid. If you leave the actuation, the code will be compiled, but the value of the pointer can be changed at runtime (converting pointers to int and back to pointers will not make sense again).
3 - There are some rare instances limited by C ++, where the T* p style can make the code a little more understandable, but in general you better follow the T *p style. Yes, this is a personal opinion, but it is supported by non-trivial experience.