如何构建和管理这个复杂的C数据结构?

发布于 2024-12-11 17:23:06 字数 573 浏览 0 评论 0原文

我很困惑如何在 C 中有效地管理(填充和访问)以下数据结构。简单描述一下,我有一个包含另一个结构的成员的结构,并且该结构有另一个不同结构的成员,所以四。像这样的:

typedef struct
{
    int num;
} D;

typedef struct
{
    D *boo;
} C;

typedef struct
{
    C *far;
} B;

typedef struct
{
    int foo;
    B *bar;
} A;

A *func() {
    A *var;
    // POPULATE var
}

int main(...) {
    A *a = func();
    // PRINTING
}

那么,哪种方式是管理这个数据结构的最佳方式呢?我的意思是如何填充这个 A 类型指针的数据?

想象一下,我要打印 a 保留的所有数据(在 // PRINTING 处),我想我会得到如下内容: a- >bar->far->boo->num。我不知道这是否正常工作,因此是否可靠。

I'm quite confusing how to efficiently manage (populating and accessing) the following data structure in C. To describe in brief, I have a struct that contains a member of another struct, and that struct has a member of another different struct and so forth. Something like this:

typedef struct
{
    int num;
} D;

typedef struct
{
    D *boo;
} C;

typedef struct
{
    C *far;
} B;

typedef struct
{
    int foo;
    B *bar;
} A;

A *func() {
    A *var;
    // POPULATE var
}

int main(...) {
    A *a = func();
    // PRINTING
}

So, which way is the best way to manage this data structure? I mean how am I going to populate the data for this A-typed pointer?

Imagine that I'm about to print all the data that a keeps (at // PRINTING), I guess I'm gonna have something like: a->bar->far->boo->num. I don't know whether this properly works and thus, is robust.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

↙厌世 2024-12-18 17:23:06

这在例如Python中不会更容易,如果你选择这样一个分散的设计,那么管理起来自然会有点痛苦。

打印就像你说的那样工作,C 的 -> 运算符通常就是这样使用的。当然,如果结构不“完整”,可能存在 NULL 指针,则需要在取消引用指针之前检查这一点,否则将出现未定义的行为。

填充可能最好通过编写函数在每一层创建一个实例来完成,然后可以在链中相互调用以设置最顶层的类型:

D* d_create(int num);
C* c_create(int num);
B* b_create(int num);

A* a_create(int foo, int num)
{
   A* a = malloc(sizeof *a);
   if(a != NULL)
   {
     a->foo = foo;
     a->bar = b_create(num);
     if(a->bar != NULL)
       return a;
     free(a);
   }
   return NULL;
}

这有点麻烦,因为所有实际数据(foonum)必须传递到创建 A 实例的顶级函数,但它可以工作并且非常简单。

请注意,我们如何通过确保 B 指针为非 NULL 来捕获来自较低级别内存分配器的错误。这些类型的检查在其他create函数中也是必要的。

This wouldn't be any easier in e.g. Python, if you're selecting such a scattered design then it's going to be a bit painful to manage, naturally.

The printing would work just as you say, C's -> operator is typically used just like that. Of course, if there can be NULL pointers where the structure is not "complete" you need to check for that before dereferencing the pointer, or you will have undefined behavior.

Population would probably be best done by writing functions to create an instance at each layer, which can then call each other in a chain to set up the top-most type:

D* d_create(int num);
C* c_create(int num);
B* b_create(int num);

A* a_create(int foo, int num)
{
   A* a = malloc(sizeof *a);
   if(a != NULL)
   {
     a->foo = foo;
     a->bar = b_create(num);
     if(a->bar != NULL)
       return a;
     free(a);
   }
   return NULL;
}

This is a bit cumbersome since all the actual data (foo and num) must be passed in to the top-level function that creates an instance of A, but it works and is very straight-forward.

Notice how we catch errors from the lower-level memory allocators, by making sure the B pointer is non-NULL. These kinds of checks would be necessary in the other create-functions, too.

牛↙奶布丁 2024-12-18 17:23:06

如果不知道为什么选择使用指针,就不可能回答“我如何管理这个”。如果每个A拥有自己的B等等,那么在分配A的时候就需要分配B >,并在释放 A 时释放它。但在这种情况下,指针就没用了,而且会产生额外的工作。您可以这样做:

typedef struct
{
    int num;
} D;

typedef struct
{
    D boo;
} C;

typedef struct
{
    C far;
} B;

typedef struct
{
    int foo;
    B bar;
} A;

A func() { // don't necessarily need to return a pointer here either
    A var;
    var.foo = 1;
    var.bar.far.boo.num = 2;
    return var;
}

如果指针的原因是您可能有多个 A 实例,它们都指向 B 的同一个实例,那么您需要决定您如何知道 B 的实例何时不再使用并且可以被释放。有一些通用的解决方案,例如引用计数,或者可能有一些特定于您的应用程序的解决方案可以使问题的答案变得容易。

It's not possible to answer "how do I manage this", without knowing why you've chosen to use pointers. If each A owns its own B and so on, then you need to allocate the B when you allocate the A, and free it when you free the A. But in that case the pointer is useless and creates extra work. You could just have done:

typedef struct
{
    int num;
} D;

typedef struct
{
    D boo;
} C;

typedef struct
{
    C far;
} B;

typedef struct
{
    int foo;
    B bar;
} A;

A func() { // don't necessarily need to return a pointer here either
    A var;
    var.foo = 1;
    var.bar.far.boo.num = 2;
    return var;
}

If the reason for the pointer is that you could have several instances of A that all point to the same instance of B, then you need to decide how you will know when that instance of B is no longer in use and can be freed. There are some general-purpose solutions like reference counting, or there might be something specific to your application that makes the answer to the question easy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文