简体   繁体   English

定义一个结构,该结构的成员指向另一个成员

[英]Define a struct with a member pointing to another member

I'm trying to program a network in C. I have nodes which are linked to each other and I 'd like to do that by making the struct member point to another member (not to another node, because I want to preserve the identity of the links). 我正在尝试用C编程网络。我有相互链接的节点,我想通过使struct成员指向另一个成员(而不是另一个节点)来实现这一点,因为我想保留身份的链接)。 The code I made to do that is something like: 我要做的代码是这样的:

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

but this is not right as node is not a variable but a type of variable (this is already discussed as an error in another QA: first you have to define a variable of node type and then apply the .link, but this doesn't help here). 但这是不对的,因为节点不是变量而是变量类型(这在另一个质量检查中已经作为错误进行了讨论:首先,您必须定义节点类型的变量,然后应用.link,但这不是在这里帮助)。 There's also a QA called "Struct member point at another struct member" but they don't do it from definition and it is not so clear how to generalize it (at least for me). 还有一个称为“结构成员指向另一个结构成员”的质量检查,但他们不是从定义中进行的,而且不清楚如何将其归纳(至少对我而言)。

Is it a correct way to do this? 这是正确的方法吗?

The problem is that the C language doesn't let you create the type you want. 问题是C语言不允许您创建所需的类型。 You need a type T with the property *T has the same type as T . 你需要一个类型T与物业*T具有相同类型的T You can't do that. 你不能那样做。 (Well, function pointers have that property, but that's an irrelevant technicality.) (好吧,函数指针具有该属性,但这与技术无关。)

You have to introduce a new name. 您必须引入一个新名称。 C only lets you do this with structs or similar constructions. C仅允许您使用结构或类似构造来执行此操作。

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

This will get you what you want. 这将为您提供所需的东西。 Now, in order to go from a struct link * to a struct node * , you'll have to do some pointer math: 现在,为了从struct link *struct node * ,您必须做一些指针数学运算:

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

This is also provided by the container_of macro, which is not part of the C standard, but you can find a definition for it online. 这也是由container_of宏提供的,它不是C标准的一部分,但是您可以在线找到它的定义。

Or, you could just go the traditional route. 或者,您可以走传统路线。

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

Is this what you are after? 这是你所追求的吗?

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;
}

I've used void* for the link for the reason expressed by Dietrich: you want a pointer to the link to be the same type as the link. 由于Dietrich表示的原因,我对链接使用了void* :您希望指向链接的指针与链接的类型相同。 This effectively means a cast, so why not just use a generic pointer? 这实际上意味着强制转换,那么为什么不只使用通用指针呢?

Membership in a structure, generalized or specific, is not an attribute of C data types. 通用或特定结构中的成员资格不是C数据类型的属性。 There is therefore no way to declare a pointer that can only point to a structure member, and not to any other variable of compatible type. 因此,没有办法声明只能指向结构成员,而不能指向任何其他兼容类型变量的指针。

On the other hand, you don't need to do anything special to declare a pointer that can point to a member of another structure. 另一方面,您无需执行任何特殊操作即可声明可以指向另一个结构的成员的指针。 You just need a pointer to that member's data type, and structure membership is irrelevant to that data type. 您只需要指向该成员的数据类型的指针,并且结构成员资格与该数据类型无关。

For example, you can have 例如,您可以

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 */
};

In that case, it might make sense to do something like this: 在这种情况下,执行以下操作可能很有意义:

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

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

Overall, though, I think this is kind of convoluted. 总的来说,我认为这有点令人费解。 There is probably a better way to structure your data. 可能有更好的方法来组织数据。

Update: 更新:

Based on your description of what you're after: 根据您对所追求的内容的描述:

[...] links are bidirectional, if I destroy one link (say the one that links node 1 to node 3) I'll need to destroy the node 1 link AND the corresponding link from node 3. Then I need to know more than just who is link to who. 链接是双向的,如果我销毁一个链接(例如,将节点1链接到节点3的链接),则需要销毁节点1的链接和来自节点3的相应链接。然后我需要了解更多不仅仅是谁链接到谁。 I need to know which link they are using. 我需要知道他们正在使用哪个链接。

there are at least two possible solutions, depending on details of how your nodes are structured. 至少有两种可能的解决方案,具体取决于节点结构的详细信息。 If they are structured like I show above, with an array (dynamic or not) of pointers to other nodes, then your general idea simply won't work. 如果它们的结构如我上面显示的那样,并且具有指向其他节点的指针数组(无论是否动态),那么您的一般想法将完全无效。 That's because the position of each link within an array of links will change as you delete other links (supposing that you close the gaps). 这是因为在删除其他链接时(假设您缩小了间距),链接数组中每个链接的位置都会改变。 Instead, you can just scan: 相反,您可以扫描:

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 ... */
}

If one node's links to others are stored in separate members, on the other hand, then you could indeed provide a double-pointer by which to remove links from the parent, but the presence of member k in your original structure tells me that's not your situation. 另一方面,如果一个节点与其他节点的链接存储在单独的成员中,则您确实可以提供一个双指针,通过该指针可以从父节点删除链接,但是原始结构中成员k的存在告诉我,这不是您的情况。

Ok, this is how I finally solved it in my program: 好的,这就是我最终在程序中解决它的方式:

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

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

Basicly, I defined two structures: one is the NODE type, which contains the information of how connected is the node and a vector of LINKs, and the other is the structure LINK which contains the information of the link itself, I mean which nodes the link connects. 基本上,我定义了两种结构:一种是NODE类型,它包含节点如何连接以及LINK向量的信息,另一种是LINK结构,其中包含链接本身的信息,我的意思是链接连接。

With these two I'm able to create the network of nodes with a connectivity following a Poisson distribution, and then destroy each link one by one, choosing one link at random from a list and then redirecting the pointers of each node to NULL. 通过这两个,我能够按照Poisson分布创建具有连通性的节点网络,然后一个一个地破坏每个链接,从列表中随机选择一个链接,然后将每个节点的指针重定向到NULL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM