6

我将很快开始在操作系统课程中使用 C,并且我正在阅读有关使用 C 的最佳实践,以便以后减少头痛。

这一直是我关于阵列的第一个问题,因为它们很容易搞砸。

将数组及其关联变量包含在结构中的长度捆绑在一起是一种常见的做法吗?

我从未在书中见过它,通常他们总是将两者分开或使用类似 sizeof(array[]/array[1]) 之类的交易。

但是通过将两者包装到一个结构中,您可以通过值和引用传递结构,除非使用指针,否则您无法真正使用数组,在这种情况下,您必须再次跟踪数组长度.

我开始使用 C,所以上面的内容可能是非常错误的,我还是个学生。

干杯,凯。

4

11 回答 11

6

是的,这是在 C 中的一个很好的实践。将相关值包装到包含结构中是完全合乎逻辑的。

我会走得更远。永远不要直接修改这些值也可以满足您的目的。而是编写函数,将这些值作为一对在您的结构中起作用,以更改长度和更改数据。这样你就可以添加不变的检查,也可以很容易地测试。

于 2009-03-19T13:15:53.980 回答
4

当然,你可以这样做。不确定我是否称其为最佳实践,但让 C 相当基本的数组更易于管理当然是个好主意。如果您需要动态数组,则几乎需要将进行簿记所需的各个字段组合在一起。

在这种情况下,有时您有两种大小:一种是当前的,一种是已分配的。这是一种权衡,您可以用更少的分配来换取一定的速度,但需要付出一点内存开销。

很多时候数组只在本地使用,并且是静态大小的,这就是为什么sizeof操作符可以很方便地确定元素数量的原因。顺便说一句,您的语法与此略有不同,这是它通常的外观:

int array[4711];
int i;

for(i = 0; i < sizeof array / sizeof *array; i++)
{
  /* Do stuff with each element. */
}

请记住,这sizeof不是一个函数,括号并不总是需要的。

编辑:与您描述的完全一样的包装的一个真实示例是glib提供的GArray类型。声明的用户可见部分正是您所描述的:

typedef struct {
  gchar *data;
  guint len;
} GArray;

程序应尽可能使用提供的 API 来访问数组,而不是直接戳这些字段。

于 2009-03-19T13:14:45.450 回答
4

有三种方式。

  1. 对于静态数组(非动态分配且未作为指针传递),大小在编译时是已知的,因此您可以使用sizeof运算符,如下所示:sizeof(array)/sizeof(array[0])
  2. 使用终止符(最后一个数组元素的特殊值,不能用作常规数组值),如以空字符结尾的字符串
  3. 使用单独的值,作为结构成员或自变量。这并不重要,因为所有使用数组的标准函数都采用单独的大小变量,但是将数组指针和大小合并到一个结构中会增加代码的可读性。我建议使用为您自己的功能提供更清晰的界面。请注意,如果你通过值传递你的结构,被调用的函数将能够改变数组,但不能改变大小变量,所以传递结构指针将是一个更好的选择。
于 2009-03-19T13:21:48.257 回答
2

对于公共 API,我会使用数组和大小值分开。这就是我知道的大多数(如果不是全部)c 库中的处理方式。你如何在内部处理它完全取决于你。因此,使用结构加上一些辅助函数/宏来为您完成棘手的部分是一个好主意。重新考虑如何插入或删除一个项目总是让我头疼,所以这是一个很好的问题来源。解决一次和通用的问题,可以帮助您从一开始就解决错误。动态和通用数组的一个很好的实现是kvec

于 2009-03-19T13:41:26.370 回答
2

我会说这是一个很好的做法。事实上,在 C++ 中他们将其放入标准库并调用它就足够了vector。每当您在 C++ 论坛中谈论数组时,您都会被要求使用数组的回答淹没vector

于 2009-03-19T14:05:58.260 回答
1

我认为这样做没有任何问题,但我认为通常不这样做的原因是由于这种结构产生的开销。出于性能原因,大多数 C 是裸机代码,因此通常会避免抽象。

于 2009-03-19T13:14:37.150 回答
1

我也没有在书中看到太多这样的事情,但我现在一直在做同样的事情。将这些东西“打包”在一起似乎很有意义。例如,如果您需要从方法返回分配的数组,我发现它特别有用。

于 2009-03-19T13:17:24.180 回答
1

如果您使用静态数组,则可以使用 sizeof 运算符访问数组的大小。如果将其放入结构中,则可以按值、引用和指针将其传递给函数。通过引用和指针传递参数在汇编级别是相同的(我几乎可以肯定)。

但是如果你使用动态数组,你在编译时并不知道数组的大小。因此,您可以将此值存储在结构中,但您也将仅在结构中存储指向数组的指针:

struct Foo {
  int *myarray;
  int size;
};

所以你可以按值传递这个结构,但你真正要做的是将指针传递给 int(指向数组的指针)和 int(数组的大小)。

在我看来,它对你没有多大帮助。唯一的优点是您将大小和数组存储在一个地方,并且很容易获得数组的大小。如果您将使用大量动态数组,您可以这样做。但是,如果您将使用少量数组,则更容易不使用结构。

于 2009-03-19T13:40:48.697 回答
0

我从来没有见过它这样做,但我已经十多年没有做过操作系统级别的工作了...... :-) 乍一看似乎是一种合理的方法。唯一需要注意的是确保尺寸以某种方式保持准确......根据需要计算没有那个问题。

于 2009-03-19T13:16:17.210 回答
0

考虑到您可以计算数组的长度(以字节为单位,即不是元素数),并且编译器会将 sizeof() 调用替换为实际值(它不是函数,对它的调用被编译器替换为它'返回'的值),那么你想要将它包装在结构中的唯一原因是为了可读性。

这不是一种常见的做法,如果您这样做,查看您的代码的人会认为长度字段是一些特殊值,而不仅仅是数组大小。这是你的提案中潜伏的危险,所以你必须小心地正确评论它。

于 2009-03-19T13:19:06.203 回答
0

我认为您问题的这一部分是倒退的:

“但是通过将两者包装到一个结构中,您将能够通过值和引用传递结构,除非使用指针,否则您无法真正使用数组,在这种情况下,您必须再次跟踪数组长度。”

传递数组时使用指针是默认行为;就按值传递整个数组而言,这不会给您带来任何好处。如果你想复制整个数组而不是让它衰减到一个指针,你需要将数组包装在一个结构中。有关更多信息,请参阅此答案:

可以按值将数组传递给递归函数吗?

这里更多的是关于数组的特殊行为:

http://denniskubes.com/2012/08/20/is-c-pass-by-value-or-reference/

于 2014-12-14T17:51:06.650 回答