【问题标题】:Storing data efficiently in an array有效地将数据存储在数组中
【发布时间】:2018-06-22 03:49:13
【问题描述】:

问题如下:

我将 ID 为 (e.g. 23,53,12,64...) 的错误代码存储在一个预定义长度 (e.g. 10) 的数组中。

现在我想在这些代码中存储一些额外的字节 (e.g. **23** (data: 102, 340), **53** (data: 10), **12** (data: 46, 23, 64, 12), **64** (data: 1,2,3))

几乎每个错误代码的数据长度都不同。

关于内存消耗,存储这些额外字节的最佳方式是什么?

我的想法是计算存储这些额外字节所需的最大内存。

如果我有 30 个错误代码并且我希望能够存储其中的 10 个(如果它们发生),那么可以通过将附加字节数相加来计算存储附加字节的最大内存那些需要最多额外字节的错误代码。因此,当 10 个错误发生时,需要最多的额外字节,存储额外字节的数组就足够了。

一个错误代码一次只出现一次。

当发生错误时,我将额外的字节保存到这个数组中,并将一个“指针”(它只是这个数组的索引)存储到错误代码中,额外的字节从这里开始。

但是如果发生错误并且我删除错误,这会导致碎片。

对这个数组进行碎片整理会增加 CPU 的开销。

有什么想法吗?我需要避免动态内存分配。

【问题讨论】:

  • 您需要分配足够的内存来处理最坏的情况,仅此而已。分配比“有时”少的内存是没有意义的。您的程序要么可以处理最坏的情况,要么不能。
  • 不要想象问题,触发它们,然后解决它们。
  • 30 是一个非常小的数字。不要为“内存浪费”而烦恼,除非您的设备上的内存真的很少。
  • 在不浪费内存的情况下,为最坏的情况提供足够的字节......听起来就像一只猫在咬自己的尾巴。请考虑区分平均情况和最坏情况是很常见的。如果您必须为最坏的情况做好准备,那么对浪费内存的怀疑......有点没用。您可以考虑优化使用位。 64 个不同的错误代码可以存储在 6 位而不是 8 位中。使用lossless data compression 可能更有效,但在不了解可能数据的确切特征的情况下,无法预测准确/最差压缩率。
  • 我经常与新手嵌入式程序员进行这样的讨论。最重要的是,他们永远不会真正知道他们“存钱”是为了什么。下雨天之类的。 “拥有这些字节可能很好”不是常识。有什么用?

标签: c memory


【解决方案1】:

听起来您有一个数组来存储错误 ID,而另一个数组来存储所有错误的附加字节。 (您是否还有另一个数组来存储指向每个错误的附加字节的指针?)您关心的是管理 additional_bytes 数组和指针。对吗?

不要使用带有指针的单独数组,而是将所有内容存储在单个结构数组中。

首先声明一个包含与错误相关的所有信息的结构。

typedef struct ErrorInfo
{
    unsigned int error_id;
    uint8_t additional_data[MAX_ADDITIONAL_BYTES_PER_ERROR];
} ErrorInfo;

然后分配一个数组来存储多个错误。

ErrorInfo errors_array[MAX_NUMBER_OF_ERRORS];

设置这样的错误:

errors_array[0].error_id = 23;
errors_array[0].additional_data[0] = 102;
errors_array[0].additional_data[1] = 340;  <--- Note that 340 will overflow a byte!

这应该比您的设计使用更少的内存,因为您不再需要为每个错误记录指向额外字节的指针。这也消除了您的碎片整理问题,因为每个错误的附加字节在结构数组中都有一个保留位置,您不再需要在单独的添加字节数组中管理它们的位置。

如果您必须将所有错误的所有附加字节存储在单独的数组中,则只需为每个错误使用固定(永久)偏移量。错误号n 的附加字节的偏移量等于(n - 1) * MAX_ADDITIONAL_BYTES_PER_ERROR。这将在错误之间的数组中留下一些空字节,但它将消除存储指针和管理碎片的需要。

【讨论】:

  • 感谢您的回答!是的,你没看错。您描述的方法是我现在使用的方法。但是如果只有一个错误,需要10个字节的外部数据,而其他的需要0个,那么使用这种方法会分配大量内存。
  • @tomi 您的评论与您的​​问题相矛盾。如果每个错误插槽(10 个?)都可能包含需要 10 个额外字节的错误 ID,那么您必须为最坏的情况分配(10 个额外 * 10 个插槽)。当最坏的情况没有发生时,其中一些字节可能未被使用。但不要担心。 100 字节不是很多。 YAGNI。如果您在开发后期遇到内存紧缩,很可能会在其他地方有更好的节省机会。
  • 谢谢。不,一个错误代码只能出现一次,并且出现次数存储在计数器中。
【解决方案2】:

对于没有动态更改数据的只读解决方案,我会考虑使用运行长度方法。代码、长度、数据[长度]、代码、长度、数据[长度]等...

访问速度很慢,但如果您没有索引,那么您也必须在数组中搜索才能找到所需的代码。

您可以编写一些在主机而不是目标上进行编码的小程序,并将数组作为 C 代码打印到文件中。主机将使用一种浪费的方法,其中数据大小是您将遇到的最大值。

【讨论】:

    猜你喜欢
    • 2012-07-30
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    相关资源
    最近更新 更多