将指向相同类型的结构成员的结构的指针分配给指向相同类型的结构的另一个指针

时间:2018-10-13 00:02:21

标签: c pointers struct

这个问题即使对于我来说也听起来很混乱,它似乎很明显或已经回答了,但是我进行了很多搜索,尽管我发现了一些有趣的东西,但我并没有找到确切的答案。以下是一些 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

2 个答案:

答案 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_structstruct NodeNode。在这种情况下,struct Node_structNode是同义词,而struct Node是不完整的结构类型(或者,至少问题中的任何代码都未完成)。它与struct Node_structNode完全无关,只是碰巧在结构内部被引用。

使用这种表示法时,强制转换是“必需的”,因为您要在指向不相关类型(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;
    }
}