我有这个结构定义:
typedef struct node_bst
{
int data;
struct node_bst *lchild;
struct node_bst *rchild;
struct node_bst *parent;
} node_bst;
我尝试使用以下方法创建指向结构的指针:
node_bst *root;
并像这样分配内存:
root= malloc(sizeof(node_bst));
现在,为了初始化其中的数据项,我尝试了这个语句(从通常的结构变量初始化中得到启示):
*root= {0, NULL, NULL, NULL};
但是编译器抛出了一个错误
错误:'{'标记
之前的预期表达式
我查了一下,发现我需要像这样对它进行类型转换:
*root= (node_bst) {0, NULL, NULL, NULL};
现在它工作正常,但我的问题是,为什么我需要这样做?
我希望编译器已经知道root是指向node_bst类型结构变量的指针。那么为什么需要对rvalue进行类型转换呢?
另一件奇怪的事情:
int *a= malloc(sizeof(int));
*a= 4;
这很好用。
答案 0 :(得分:10)
没有施法。
在本声明中
*root = (node_bst) {0, NULL, NULL, NULL};
使用了所谓的复合文字(node_bst) {0, NULL, NULL, NULL}
,它对应于node_bst
类型的对象,并且此对象被分配给对象*root
。
来自C标准(6.5.2.5复合文字)
3 post fi x表达式,由带括号的类型名称组成 然后是括号括起来的初始化列表,是一种化合物 文字。它提供了一个未命名的对象,其值由 初始化列表。
另一种方法是分配动态分配对象的每个数据成员。例如
root->data = 0;
root->lchil = NULL;
root->rchil = NULL;
root->parent = NULL;
至于这句话
*root= {0, NULL, NULL, NULL};
然后从C的角度来看它是无效的。您只能在声明中使用支撑初始化。
如果将程序编译为C ++程序,该语句将有效。
答案 1 :(得分:4)
此处使用的语法不是类型转换,而是复合文字。这些在C standard:
的6.5.2.5节中定义3 后缀表达式由带括号的类型名称后跟括号括起的初始值设定项列表组成 复合文字。它提供了一个未命名的对象,其值由初始化列表给出。
在分配给struct
作为整体时,必须使用复合文字。
在这种情况下,您不需要这种语法:
int *a= malloc(sizeof(int));
*a= 4;
由于*a
的类型为int
,4
是一个简单的整数常量,可以直接分配给*a
。
另请注意,涉及指针的事实无关紧要。在这种情况下你需要做同样的事情:
node_bst root;
root= (node_bst){0, NULL, NULL, NULL};
这与以下不同:
node_bst root = {0, NULL, NULL, NULL};
前一种情况是赋值,而后一种情况是初始化。初始化只能在定义变量时完成(甚至在函数外部),而赋值可以在任何时间完成。
初始化的语法(参见标准的第6.7.9节)只允许括号括起的值列表,而赋值则需要复合文字。
此外,正如评论中所提到的,您仍然可以在初始化中使用复合文字,复合文字的生命周期为当前范围,您可以使用其地址。
以下是一个有趣的例子:
char *str = (char[]){ "My string" };
str[3] = 'S';
这里,正在修改复合文字,这是允许的。但如果你这样做:
char *str = "My string";
str[3] = 'S';
您将尝试修改字符串文字,并且很可能会出现分段错误。