这个问题即使对于我来说也听起来很混乱,它似乎很明显或已经回答了,但是我进行了很多搜索,尽管我发现了一些有趣的东西,但我并没有找到确切的答案。以下是一些 C 代码,这些代码可以更好地显示我的疑问:
typedef struct Node_struct {
char keyLine[100];
int occurrences;
struct Node* leftChild;
struct Node* rightChild;
struct Node* parent;
} Node;
typedef struct Tree_struct {
Node* root;
} Tree;
int insertNode(Tree* myTree, Node* newNode) {
...
Node* currentNode = myTree->root;
...
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = (Node*)currentNode->leftChild;
}
...
}
此代码正确吗?由于currentNode
的类型为Node*
,而currentNode->leftChild
的类型为struct Node*
,因此我必须强制转换(Node*)currentNode->leftChild
,以便可以将其分配给{{1} }。但是我不确定这是否正确,必要,或者是否有更好的方法可以做到这一点。
类似地,我也有这个:
currentNode
答案 0 :(得分:4)
假设问题中的代码是这样写的:
typedef struct Node { // Not Node_struct as in the question!
char keyLine[100];
int occurrences;
struct Node* leftChild;
struct Node* rightChild;
struct Node* parent;
} Node;
然后,名称Node
将是struct Node
的同义词(别名)。 (对于任何typedef X Y;
,Y
都是类型X
的同义词-在您的情况下,X
将是struct Node
,而Y
将是节点。)
演员:
currentNode = (Node *)currentNode->leftChild;
将是不必要的(但大多数情况下是无害的),因为它将是无操作的-类型struct Node *
和Node *
将是同一指针类型的两个名称。与此类似:
coverNode->leftChild = (struct Node *)newNode;
施放是不必要的,但(大多数)无害。将演员与演员混淆的风险很小。最好在可能的情况下避免强制转换,而如果没有强制转换,则最好写成这样:
currentNode = currentNode->leftChild;
coverNode->leftChild = newNode;
typedef struct Node_struct {
char keyLine[100];
int occurrences;
struct Node* leftChild;
struct Node* rightChild;
struct Node* parent;
} Node;
现在我们正在使用三种类型的名称:struct Node_struct
,struct Node
和Node
。在这种情况下,struct Node_struct
和Node
是同义词,而struct Node
是不完整的结构类型(或者,至少问题中的任何代码都未完成)。它与struct Node_struct
或Node
完全无关,只是碰巧在结构内部被引用。
使用这种表示法时,强制转换是“必需的”,因为您要在指向不相关类型(struct Node *
和struct Node_struct *
)的指针之间进行转换。幸运的是,有规则说所有结构类型指针都是可以相互转换的,并且必须具有相同的大小和对齐要求(C11 §6.2.5 Types ¶28和§6.3.2.3 Pointers ¶7)。
但是您应该删除_struct
的{{1}}部分,以使该答案的第一部分的规则适用。在C语言中,使用(IMO)是明智的:
Node_struct
,以便您以后可以使用typedef struct SomeTag SomeTag;
等。第一个SomeTag *
在标签名称空间中,并且与第二个SomeTag
冲突,第二个SomeTag
在普通标识符名称空间中。参见C11 §6.2.3 Name spaces of identifiers。
另请参阅:
答案 1 :(得分:2)
在c++
中,当您说struct Node
时,Node
立即成为一种类型。所以,你可以说:
struct Node {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
};
struct Tree {
Node *root;
};
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
但是,在c
中,它只是在“ tag”名称空间中,并且不是定义类型。因此,您想要:
typedef struct Node {
char keyLine[100];
int occurrences;
struct Node *leftChild;
struct Node *rightChild;
struct Node *parent;
} Node;
typedef struct Tree_struct {
Node *root;
} Tree;
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
或者,您可以使用转发声明:
// forward declaration
struct Node;
typedef struct Node Node;
struct Node {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
};
typedef struct Tree_struct {
Node *root;
} Tree;
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
请注意,struct
名称不一定 必须与类型名称匹配:
// forward declaration
struct Node_struct;
typedef struct Node_struct Node;
struct Node_struct {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
};
typedef struct Tree_struct {
Node *root;
} Tree;
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
要允许您的两个结构交叉链接,我们可以这样做:
// forward declaration
struct Node_struct;
typedef struct Node_struct Node;
struct Tree_struct;
typedef struct Tree_struct Tree;
struct Node_struct {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
Tree *tree;
};
struct Tree_struct {
Node *root;
};
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}