在C中使用第一个数组元素作为数组长度是一种很好的编程习惯吗?
因为在 C 中必须在定义数组时声明数组长度,所以使用第一个元素作为长度是否可以接受,例如
int arr[9]={9,0,1,2,3,4,5,6,7};
然后使用这样的函数来处理数组:
int printarr(int *ARR) {
for (int i=1; i<ARR[0]; i++) {
printf("%d ", ARR[i]);
}
}
我看不出这有什么问题,但更愿意先咨询有经验的 C 程序员。我将是唯一一个使用代码的人。
回答
好吧,从某种意义上说,您有一个数组,其中元素的含义不同,这很糟糕。将元数据与数据一起存储并不是一件好事。只是为了稍微推断一下你的想法。我们可以使用第一个元素来表示元素大小,然后使用第二个元素来表示长度。尝试使用两者编写一个函数;)
还值得注意的是,使用这种方法,如果数组大于元素可以容纳的最大值,则会出现问题,这对于char数组来说是一个非常重要的限制。当然,您可以使用前两个元素来解决它。如果您有浮点数组,也可以使用强制转换。但是我可以向您保证,您会因此遇到难以追踪的错误。除其他外,字节序可能会导致很多问题。
它肯定会让几乎每个经验丰富的 C 程序员感到困惑。这并不是反对这种想法的真正合乎逻辑的论据,而是一种务实的论据。即使这是一个好主意(事实并非如此),您也必须与每个与您的代码有任何关系的程序员进行长时间的对话。
实现相同目的的合理方法是使用结构。
struct container {
int *arr;
size_t size;
};
int arr[10];
struct container c = { .arr = arr, .size = sizeof arr/sizeof *arr };
但是在任何我会使用类似上面的东西的情况下,我可能不会使用数组。我会改用动态分配:
const size_t size = 10;
int *arr = malloc(sizeof *arr * size);
if(!arr) { /* Error handling */ }
struct container c = { .arr = arr, .size = size };
但是,请注意,如果您使用指针而不是数组以这种方式初始化它,则会得到“有趣”的结果。
您还可以使用灵活的数组,正如 Andreas 在他的回答中所写
回答
在 C 中,您可以使用灵活的数组成员。那就是你可以写
struct intarray {
size_t count;
int data[]; // flexible array member needs to be last
};
你分配
size_t count = 100;
struct intarray *arr = malloc( sizeof(struct intarray) + sizeof(int)*count );
arr->count = count;
这可以用于所有类型的数据。
它使 C 数组的使用更加安全(不如 C++ 容器安全,但比普通 C 数组更安全)。
不幸的是,C++ 在标准中不支持这个习语。尽管许多 C++ 编译器将其作为扩展提供,但并不能保证。
另一方面,这个 C FLA 习惯用法可能比 C++ 容器更明确,也可能更有效,因为它不使用额外的间接寻址和/或需要两次分配(想想new vector<int>)。
如果您坚持使用 C,我认为这是处理具有集成大小的可变长度数组的一种非常明确且可读的方式。
唯一的缺点是 C++ 人不喜欢它并且更喜欢 C++ 容器。
- It would be good if you mentioned that a struct can have max 1 flexible array member and that it has to be last in the struct.