【问题标题】:Embedded versus pointer in nested String-like structures嵌套类字符串结构中的嵌入与指针
【发布时间】:2019-09-08 16:28:49
【问题描述】:

在设计包含文本数据的结构时,我一直使用以下两种基本方法:

typedef struct {
    STRING address1;
    STRING address2;
    STRING city;
    STRING state;
    STRING zip;
} ADDRESS;

typedef struct {
    STRING* address1;
    STRING* address2;
    STRING* city;
    STRING* state;
    STRING* zip;
} ADDRESS;

其中 STRING 是一些可变长度的字符串存储类型。指针版本的优点是我可以存储表示数据丢失的 NULL。例如,可能没有为某些地址提供 address2。在嵌入字符串的类型中,我必须使用“空白”字符串,即长度为 0 的字符串。

使用指针有(可能)更多的代码负担,因为我必须在使用前检查每个成员是否为 NULL。然而,优势并不是那么大,因为通常也必须检查嵌入式版本。例如,如果我正在打印一个地址,我必须检查一个零长度的字符串并跳过该行。使用指针,用户实际上可以表明他们想要一个“空白”而不是一个缺失值,尽管很难看到这样做的用途。

在创建或释放结构时,指针会添加一堆额外的步骤。我的直觉是标准化嵌入式样式以节省这些步骤,但我担心可能存在隐藏的问题。这是没有根据的恐惧,还是我应该出于某些令人信服的原因使用指针?

请注意,内存使用是一个问题,但它非常小。指针版本需要更多内存,因为除了结构之外,我还存储指向结构的指针。但是每个字符串结构平均可能需要 40 个字节,所以如果我存储 4 个字节的指针,那么指针版本可能会多消耗 10% 的内存,这并不重要。可能使用空指针并不会节省大量内存,因为大多数字段都已填充。

问题是关于地址而不是字符串

一些受访者似乎很困惑,认为我在询问全局权衡,例如如何最小化我的总工作量。事实并非如此。我问的是如何设计地址,而不是字符串。 address 的成员可以有固定的数组,或者在其他情况下没有。就我的问题而言,我不关心容器的后果。

我已经说过,我能看到的唯一问题是使用指针会花费更多时间,但我得到了能够存储 NULL 的好处。然而,正如我已经说过的,这种好处似乎并不显着,但也许是出于某种原因。这就是我的问题的本质:拥有这种灵活性是否有一些隐藏的好处,我没有看到并且希望我以后有。

如果您不理解这个问题,请阅读我在下面写的初步答案(经过一些额外的思考),看看我正在寻找的答案。

【问题讨论】:

  • 我猜STRING 是一个struct,其成员跟踪已分配/使用了多少内存,以及指向所述内存的指针。但是两个答案都假设 STRING 是固定长度数组的 typedef。您可能需要清除它。
  • 你需要向我们展示STRING结构的定义。
  • 这个问题的实际答案取决于STRING 结构的定义方式。
  • 有时我使用具有固定长度数组的结构,有时我使用具有指针分配数组的嵌入式结构。假设 STRING 可能有。我在这里问的是容器的设计,而不是内容。
  • @MarkBenningfield 为什么?

标签: c pointers struct datadesign


【解决方案1】:

权衡内存使用和减少 mallocs

似乎权衡围绕两个问题:1)内存有多宝贵? 2)为字符串分配固定数量的内存是否重要,限制每个字段中存储的长度?

如果内存比其他任何东西都重要,那么指针版本可能会胜出。如果存储使用的可预测性和避免 malloc 是首选,并且将名称的长度限制在某个固定数量是可以接受的,那么固定长度版本可能是赢家。

【讨论】:

  • 我认为内存问题很小。我会在我的问题中添加评论。
  • 请注意,指针版本不一定会节省内存,因为偶尔的空指针所节省的内存是由存储指针本身的成本来弥补的。因此,例如,在我给定的情况下,有 5 个字段,因此我必须存储 5 个指针,与嵌入式版本相比,这可能会花费 5 x 8 = 40 个额外字节。
  • 在您揭示 STRING 是如何实现的之前,我们就像一群玩龙与地下城的朋友,等待着地下城主来启发我们了解我们所处世界的真实本质。 :-)
  • 很好的类比,但我建议更仔细地阅读这个问题。如果您认为 STRING 的内容会影响答案,那么您还没有理解问题。
  • 我倾向于不同意。另外两名声望比我高得多的成员也说了同样的话。事实上,他们俩都说我做出了在我的回答中无效的“假设”。
【解决方案2】:

嵌入样式的一个问题是 STRING 需要定义为类似char[MAX_CHAR + 1] 的东西,其中MAX_CHAR 是给定字段的悲观最大长度。指针样式允许分配正确的内存量。您提到的缺点是管理结构的认知开销要高得多。

【讨论】:

  • "...STRING 需要定义为char[MAX_CHAR + 1]...":不一定,目前我们完全不知道 STRING 类型是如何实现的。
  • 我的意思是每个字符串项都需要有一个悲观的最大长度。
  • 为什么?我们不知道STRING 是如何实现的。
  • 在大多数情况下,STRING结构内部都有指针,因此它具有灵活的内存结构,但这与问题无关。我的问题围绕着如何设计容器。
  • 好的,我误解了 OP 的问题
【解决方案3】:

我一直在更深入地考虑这一点,我认为在大多数情况下指针是必要的,因为区分空白和缺失很重要。这样做的原因是当输入无效或损坏或遗漏时需要丢失的数据。例如,假设从文件中读取时,文件已损坏,因此邮政编码等字段不可读。在这种情况下,数据“丢失”并且指针应该为 NULL。另一方面,让我们假设这个地方没有邮政编码,那么它就是“空白”。所以,NULL 表示用户还没有提供信息,而空白表示用户已经提供了信息并且没有问题类型。

因此,为了进一步说明使用指针的重要性,想象一个复杂的结构随着时间的推移以不同的异步步骤填充。在这里,我们需要知道哪些字段已读取,哪些未读取。除非我们使用指针(或添加额外的元数据),否则我们无法区分已回答的字段与回答为“无”的字段之间的区别。想象一下系统提示用户“邮政编码是什么?”。用户说,“这个地方没有邮政编码”。然后 5 分钟后系统再次询问,“邮政编码是多少?”。这个用例清楚地表明我们在大多数情况下都需要指针。

在这种情况下,我应该使用嵌入式结构的唯一情况是容器结构在创建时保证具有完整的数据集。

【讨论】:

  • “空”和“缺失”的区别应该在STRING本身。这样,可以将 STRING(单独)传递给函数,而不会丢失有关字符串是否存在、空或丢失的信息。换句话说,STRING 应该是自包含的。容器是使用指向 STRING 的指针还是嵌入的 STRING 与如何跟踪丢失的字符串的问题完全无关。
  • @user3386109 我不想将那种元数据添加到我的字符串容器中。
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 2012-09-23
  • 1970-01-01
  • 2010-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多