使用指向另一个成员的成员定义结构

时间:2015-11-12 22:16:52

标签: c pointers struct

我正在尝试用C编写网络。我有相互链接的节点,我想通过使struct成员指向另一个成员(而不是另一个节点,因为我想要保留链接的身份)。 我做的代码是这样的:

struct node{
    int k; //number of links
    struct node.link **link; //<- wrong
};

但这不正确,因为节点不是变量而是一种变量(在另一个QA中已经讨论过这个错误:首先你必须定义一个节点类型的变量,然后应用.link,但是这个在这里没有帮助)。还有一个名为“另一个结构成员的结构成员点”的质量保证,但他们没有从定义中做到这一点,如何概括它(至少对我而言)并不是很清楚。

这是一种正确的方法吗?

4 个答案:

答案 0 :(得分:0)

问题是C语言不能让你创建你想要的类型。您需要属性为*T的类型T与T具有相同类型。你不能这样做。 (好吧,函数指针具有该属性,但这是一个无关紧要的技术性。)

你必须引入一个新名字。 C只允许你使用结构或类似的结构。

struct link {
    struct link *ptr;
};
struct node {
    int k;
    struct link *link;
};

这会让你得到你想要的。现在,为了从struct link *转到struct node *,您必须做一些指针数学运算:

struct node *node_from_link(struct link *link) {
    return (struct node *) ((char *) link - offsetof(struct node, link));
}

这也是由container_of宏提供的,它不是C标准的一部分,但您可以在线找到它的定义。

或者,你可以走传统路线。

// Usually easier to do it this way...
struct node {
    int k;
    struct node *link;
};

答案 1 :(得分:0)

这就是你想要的吗?

struct Node
{
    int k; //number of links
    void* link; 
};

struct Node* create()
{
    struct Node* node = malloc(sizeof(struct Node));
    node->k = 0;
    node->link = 0;
    return node;
}

void link(struct Node* from, struct Node* to)
{
    from->link = &(to->link);
}

int main()
{
    struct Node* child = create();
    struct Node* parent = create();
    link(parent, child);
    return 0;
}

由于Dietrich表达的原因,我已使用void*作为链接:您希望指向链接的指针与链接的类型相同。这实际上意味着一个演员,所以为什么不使用通用指针?

答案 2 :(得分:0)

结构中的成员资格(通用或特定)不是C数据类型的属性。因此,无法声明只能指向结构成员的指针,而不能指向兼容类型的任何其他变量。

另一方面,您不需要做任何特殊的事情来声明可以指向另一个结构的成员的指针。您只需要指向该成员的数据类型的指针,结构成员资格与该数据类型无关。

例如,您可以

struct node {
    int k; /* number of links */
    struct node **links; /* points to a dynamic array of node pointers */
    struct node **one_link; /* points to a node pointer from another node */
};

在这种情况下,做这样的事情可能有意义:

struct node *n1 = /* ... */;
struct node *n2 = /* ... */;

n2->one_link = &(n1->links[3]);

总的来说,我认为这有点令人费解。可能有更好的方法来构建数据。

<强>更新

根据您对之后的描述:

  

[...]链接是双向的,如果我销毁一个链接(比如将节点1链接到节点3的链接),我需要销毁节点1链接和节点3的相应链接。然后我需要了解的不仅仅是谁与谁联系。我需要知道他们正在使用哪个链接。

至少有两种可能的解决方案,具体取决于节点结构的详细信息。如果它们的结构类似于我在上面显示的,有一个指向其他节点的指针的数组(动态或非动态),那么你的总体想法就不会起作用。这是因为链接数组中每个链接的位置会随着您删除其他链接而改变(假设您缩小了间隙)。相反,你可以只扫描:

struct node {
    int k; /* number of links */
    struct node **links; /* points to a dynamic array of node pointers */
    struct node *parent; /* points to a node that links to this one */
};

void delete_node(struct node *n) {
    if (n->parent) {
        int i;

        for (i = 0; i < n->parent->k; i += 1) {
            if (n->parent->links[i] == n) {
                /* ... delete the ith element of n->parent->links ... */
                break;
            }
        }
    }

    /* ... clean up node n ... */
}

另一方面,如果一个节点与其他节点的链接存储在不同的成员中,那么你确实可以提供一个双指针来删除父节点的链接,但是成员{{1}的存在在你的原始结构中告诉我,不是你的情况。

答案 3 :(得分:0)

好的,这就是我最终在我的程序中解决它的方法:

typedef struct node{
int k; //connectivity
struct link **enlace; //vector of LINKs
}NODE;

typedef struct link{
NODE *node1;
NODE *node2;
}LINK;

基本上,我定义了两个结构:一个是NODE类型,它包含如何连接节点和LINK向量的信息,另一个是包含链接本身信息的结构LINK,我的意思是链接连接的节点。

通过这两个,我能够创建具有遵循泊松分布的连接的节点网络,然后逐个销毁每个链接,从列表中随机选择一个链接,然后将每个节点的指针重定向到NULL。