Why would I introduce a cast when initializing a user-defined structure with a pointer?

I have this structure definition:

typedef struct node_bst { int data; struct node_bst *lchild; struct node_bst *rchild; struct node_bst *parent; } node_bst; 

I tried to create a pointer to a structure using this:

 node_bst *root; 

and allocated the following memory for him:

 root= malloc(sizeof(node_bst)); 

Now, to initialize the data elements in it, I tried this statement (taking a hint from the usual initialization of structural variables):

 *root= {0, NULL, NULL, NULL}; 

But the compiler threw an error

error: expected expression before '{token

I looked through it and found that I need to do this as follows:

 *root= (node_bst) {0, NULL, NULL, NULL}; 

Now it works fine, but my question is: why should I do this?

I expected the compiler to already know that root is a pointer to a structure variable of type node_bst. So why do you need to output the rvalue value?

Another weird thing:

 int *a= malloc(sizeof(int)); *a= 4; 

This works great.

+5
source share
2 answers

The syntax used here is not a type, but a composite literal . They are defined in section 6.5.2.5 standard C :

3 A postfix expression consisting of a type name in parentheses followed by a list of initializers enclosed in parentheses is a composite literal. It provides an unnamed object whose value is specified in the list of initializers.

An adjacent literal is required when assigning a struct as a whole.

In this case, you do not need this syntax:

 int *a= malloc(sizeof(int)); *a= 4; 

Since *a is of type int , and 4 is a simple integer constant that can be assigned directly to *a .

Note also that the fact that the pointer is involved does not matter. In this case, you will need to do the same:

 node_bst root; root= (node_bst){0, NULL, NULL, NULL}; 

This is different from:

 node_bst root = {0, NULL, NULL, NULL}; 

The first case is an assignment, and the second is initialization. Initialization can only be done while the variable is being defined (even outside the function), while assignment can be done at any time.

The initialization syntax (see section 6.7.9 of the standard) allows only a list of values ​​enclosed in curly brackets, while a composite literal is required for assignment.

In addition, as mentioned in the comments, you can still use the composite literal in the initialization, and the composite literal has the lifetime of the current area, the address of which you can take.

Here is an interesting example:

 char *str = (char[]){ "My string" }; str[3] = 'S'; 

Here the composite literal changes, which is allowed. But if you do this:

 char *str = "My string"; str[3] = 'S'; 

Instead, you try to change the string literal and most likely get a segmentation error.

+4
source

No casting.

In this statement

 *root = (node_bst) {0, NULL, NULL, NULL}; 

the so-called composite literal (node_bst) {0, NULL, NULL, NULL} , which corresponds to an object of type node_bst , and this object is assigned to the *root object.

From standard C (6.5.2.5. Component literals)

3 A postfix expression consisting of a type name in brackets and then a list of initializers enclosed in curly braces is a literal component. It provides an unnamed object whose value is given by a list of initializers.

Another approach is simply to assign each data member to a dynamically allocated object. for instance

 root->data = 0; root->lchil = NULL; root->rchil = NULL; root->parent = NULL; 

Regarding this statement

 *root= {0, NULL, NULL, NULL}; 

it is invalid from the point of view of C. You can only use corrected initialization in the declaration.

The statement will be valid if you compile the program as a C ++ program.

+10
source

Source: https://habr.com/ru/post/1266830/


All Articles