C 将指向同一类型结构成员的结构的指针指定给指向同一类型结构的另一个指针

C 将指向同一类型结构成员的结构的指针指定给指向同一类型结构的另一个指针,c,pointers,struct,C,Pointers,Struct,即使对我来说,这个问题听起来也非常令人困惑,它可能看起来很明显或者已经得到了回答,但我已经搜索了很多,虽然我发现了一些有趣的东西,但我并没有找到我问题的确切答案。下面是一些C代码,可以更好地显示我的疑问: typedef struct Node_struct { char keyLine[100]; int occurrences; struct Node* leftChild; struct Node* rightChild; struct Node* paren

即使对我来说,这个问题听起来也非常令人困惑,它可能看起来很明显或者已经得到了回答,但我已经搜索了很多,虽然我发现了一些有趣的东西,但我并没有找到我问题的确切答案。下面是一些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,以便将其分配给currentNode。但我不确定这是正确的、必要的,还是有更好的方法来做到这一点

同样,我也有这样的想法:

Node* coverNode = NULL;
...
coverNode->leftChild = (struct Node*)newNode;
<>在C++中,当你说Stutt节点时,节点[立即]成为一个类型。所以,你可以说:

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中,它只是在标记名称空间中,没有定义类型。因此,您需要:

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_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;
    }
}
<>在C++中,当你说Stutt节点时,节点[立即]成为一个类型。所以,你可以说:

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中,它只是在标记名称空间中,没有定义类型。因此,您需要:

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_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;
    }
}
应该写什么 假设问题中的代码是这样写的:

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;
那么name节点将是struct节点的同义词别名。对于任何类型的定义X Y;,Y成为类型X的同义词-在您的例子中,X是结构节点,Y是节点

演员阵容:

currentNode = (Node *)currentNode->leftChild;
这是不必要的,但基本上是无害的,因为它将是一个无操作-类型struct Node*和Node*将是同一指针类型的两个名称。同样适用于:

coverNode->leftChild = (struct Node *)newNode;
演员阵容是不必要的,但基本上是无害的。会有一个小的风险,混淆了演员的人。如果可能,最好避免强制转换,如果没有强制转换,写这些内容会更好:

currentNode = currentNode->leftChild;
coverNode->leftChild = newNode;
写了什么 现在我们有三个类型名:struct Node_struct、struct Node和Node。在这种情况下,struct Node_struct和Node是同义词,struct Node是一个不完整的结构类型,或者至少,它不是由问题中的任何代码完成的。它与struct Node\u struct或Node完全无关,只是碰巧在结构内部引用了它

使用这种表示法,强制转换是“必要的”,因为您正在转换指向不相关类型struct Node*和struct Node_struct*的指针。幸运的是,有一些规则规定所有结构类型指针都是可相互转换的,并且必须具有相同的大小和对齐要求C11和C12

但是您应该删除Node_struct的_struct部分,以使此答案第一部分的规则适用。在C中,IMO明智地使用:

typedef struct SomeTag SomeTag;
因此,您可以随后使用SomeTag*等。第一个SomeTag位于标记名称空间中,并且不会与第二个SomeTag冲突,后者位于普通标识符名称空间中。见C11

另见:

应该写什么 假设问题中的代码是这样写的:

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;
那么name节点将是struct节点的同义词别名。对于任何类型的定义X Y;,Y成为类型X的同义词-在您的例子中,X是结构节点,Y是节点

演员阵容:

currentNode = (Node *)currentNode->leftChild;
这是不必要的,但基本上是无害的,因为它将是一个无操作-类型struct Node*和Node*将是同一指针类型的两个名称。同样适用于:

coverNode->leftChild = (struct Node *)newNode;
演员阵容是不必要的,但基本上是无害的。会有一个小的风险,混淆了演员的人。如果可能,最好避免强制转换,如果没有强制转换,写这些内容会更好:

currentNode = currentNode->leftChild;
coverNode->leftChild = newNode;
写了什么 现在我们有三个类型名:struct Node_struct、struct Node和Node。在这种情况下,struct Node_struct和Node是同义词,struct Node是一个不完整的结构类型,或者至少,它不是由问题中的任何代码完成的。它与struct Node\u struct或Node完全无关,只是碰巧在结构内部引用了它

使用这种表示法,强制转换是“必要的”,因为您正在转换指向不相关类型struct Node*和struct Node_struct*的指针。幸运的是,有一些规则规定所有结构类型指针都是可相互转换的,并且必须具有相同的大小和对齐要求C11和C12

但是您应该删除Node_struct的_struct部分,以使此答案第一部分的规则适用。在C中,IMO明智地使用:

typedef struct SomeTag SomeTag;
因此,您可以随后使用SomeTag*等。第一个SomeTag位于标记名称空间中,并且不会与第二个SomeTag冲突,后者位于t中 他使用了普通的标识符名称空间。见C11

另见:


相关:名称节点是结构节点的同义词。对于任何类型的定义X Y;,Y成为X的同义词-在您的例子中,X是结构节点,Y是节点。强制转换currentNode=Node*currentNode->leftChild;是不必要的,因为它是一个no op-类型struct Node*和Node*是同一指针类型的两个名称。@JonathanLeffler关于typedef struct Node_struct{/*…*/struct Node*leftChild;/*…*/}Node。。。struct Node_struct和struct Node以及Node是否相同?我知道该节点与struct Node_struct相同,但用于声明结构成员的struct Node*呢?@JonathanLeffler稍后您可能会感谢我。安静去修好你的衣服@箭鱼:谢谢你指出我误读了这个问题。我已经“调整”了我的答案,以处理“实践”和“理论”。相关:名称节点是struct节点的同义词。对于任何类型的定义X Y;,Y成为X的同义词-在您的例子中,X是结构节点,Y是节点。强制转换currentNode=Node*currentNode->leftChild;是不必要的,因为它是一个no op-类型struct Node*和Node*是同一指针类型的两个名称。@JonathanLeffler关于typedef struct Node_struct{/*…*/struct Node*leftChild;/*…*/}Node。。。struct Node_struct和struct Node以及Node是否相同?我知道该节点与struct Node_struct相同,但用于声明结构成员的struct Node*呢?@JonathanLeffler稍后您可能会感谢我。安静去修好你的衣服@箭鱼:谢谢你指出我误读了这个问题。我已经“调整”了我的答案以处理“实践”和“理论”。你是说“标签”名称空间吗?C11@JonathanLeffler谢谢。一如既往地准确。而且,我很惊讶你能如此快速地调用在线文档,找到相关部分,并在这里发布链接。我“作弊”——我刚刚写了一个与旧问题的另一个答案非常相似的答案,而且链接仍然隐藏在我的粘贴缓冲区中。你是说“标记”名称空间?C11@JonathanLeffler谢谢。一如既往地准确。而且,我很惊讶你能以如此快的速度调用在线文档,找到相关的部分,并在这里发布链接。我“作弊”——我刚刚写了一个非常类似于另一个老问题的答案,甚至还将链接隐藏在我的粘贴缓冲区中。