【问题标题】:Array of structs vs. Array of pointers to structs结构数组与结构指针数组
【发布时间】:2017-02-19 14:58:00
【问题描述】:

当我继续学习 C 语言时,我产生了疑问。使用每个元素都是结构的数组和使用每个元素都是指向相同类型结构的指针的数组之间有哪些区别。在我看来,您可以平等地使用两者(尽管在指针中您必须处理内存分配)。有人可以解释一下在哪种情况下使用其中一种更好吗?

谢谢。

【问题讨论】:

  • 一个例子:使用qsort对指针数组进行排序可能比对结构数组排序更快(如果结构非常大),因为交换两个指针会更快而不是交换两个结构。
  • ^ OTOH,对结构数组的顺序传递将更加缓存友好,并且在每一步都不需要额外的间接。
  • 我不认为这个问题太宽泛:每种方法的优缺点都有一定程度的个人意见,但问题是真正的询问并列出两种解决方案的相关特征似乎可行。

标签: c data-structures


【解决方案1】:

结构数组和结构指针数组是组织内存的不同方式。

结构数组具有以下优点:

  • 使用struct s *p = calloc(n, sizeof(*p)); 可以轻松地一步动态分配这样一个数组。
  • 如果数组是封闭结构的一部分,则根本不需要单独的分配代码。本地数组和全局数组也是如此。
  • 数组是一个连续的内存块,指向下一个和前一个元素的指针可以很容易地计算为struct s *prev = p - 1, *next = p + 1;
  • 访问数组元素成员可能会更快,因为它们靠近内存,从而提高缓存效率。

它们也有缺点:

  • 数组的大小必须显式传递,因为无法从指向数组的指针中得知它有多少元素。
  • 表达式 p[i].member 生成一个乘法,如果结构的大小不是 2 的幂,这在某些架构上可能代价高昂。
  • 更改元素的顺序代价高昂,因为它可能涉及复制大量内存。

使用指针数组有以下优点:

  • 可以通过分配一个额外的元素并将其设置为NULL 来确定数组的大小。此约定用于提供给main() 函数的命令行参数argv[] 数组。
  • 如果不使用上述约定,并且单独传递元素的数量,则可以使用NULL 指针值来指定缺失的元素。
  • 只需移动指针即可轻松更改元素的顺序。
  • 可以使多个元素指向同一个结构。
  • 重新分配数组更容易,因为只有指针数组需要重新分配,可选择保持单独的长度和大小计数以最小化重新分配。增量分配也很容易。
  • 表达式 p[i].member 生成简单的移位和额外的内存访问,但可能比结构数组的等效表达式更有效。

还有以下缺点:

  • 分配和释放这个间接数组比较麻烦。需要一个额外的循环来分配和/或初始化数组指向的结构。
  • 对结构元素的访问涉及额外的内存间接。如果在同一个函数中访问多个成员,编译器可以为此生成有效的代码,但并非总是如此。
  • 不能从指向给定元素的指针派生指向相邻结构的指针。

编辑:正如 David Bowling 所暗示的那样,可以通过一方面分配结构数组和指向第一个元素的单独指针数组来结合这两种方法的一些优点大批。这是实现排序顺序的便捷方式,甚至可以使用单独的指针数组(如数据库索引)实现多个伴随排序顺序。

【讨论】:

  • 我想指出,我已经确定了结构数组的以下问题:除了索引之外,还不清楚这些数组的元素是否应该通过指针或引用访问。允许这样的双重访问看起来“不干净”(打破抽象障碍,允许多种方式访问​​同一位置),因此容易出错(例如,如果需要重新分配数组)。只允许通过索引进行访问会增加额外的间接性和计算,并且使得评估一些在数组项上获取结构引用的函数变得很棘手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 2012-06-04
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多