Присвоить указатель на структуру, которая является членом структуры того же типа, другому указателю на структуру того же типа - PullRequest
0 голосов
/ 13 октября 2018

Этот вопрос звучит очень запутанно даже для меня, и может показаться очевидным или уже отвеченным, но я много искал и, хотя я нашел интересные вещи, я не нашел ответа именно на мой вопрос.Вот код 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;

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Что следует написать

Предположим, код в вопросе был написан так:

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 будет Node.)

Приведение в:

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 Типы ¶28 и §6.3.2.3 Указатели ¶7).

Но вы должны отбросить _struct часть Node_struct, чтобы применить правила первой части этого ответа.В C (IMO) целесообразно использовать:

typedef struct SomeTag SomeTag;

, чтобы впоследствии можно было использовать SomeTag * и т. Д. Первый SomeTag находится в пространстве имен тегов и не конфликтует со вторымSomeTag, который находится в пространстве имен обычных идентификаторов.См. C11 §6.2.3 Пространства имен идентификаторов .

См. Также:

0 голосов
/ 13 октября 2018

В 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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...