在 C 中,我必须将数组传递给单个变量中的函数,并且在程序运行之前不知道数组的大小。纸上解决方案是在数组中添加一个额外的元素,用于存储数组的大小(我认为这称为“哨兵值”)。好的,但我在实现这个时遇到问题。
将 array[] 作为函数参数传递似乎不起作用。我想我可以发送一个指向第一个元素的指针,但是如何访问数组的其余部分?
在 C 语言中,在大多数情况下,数组会衰减为指向其第一个元素的指针:
6.3.2.1 左值、数组和函数指示符
[...] 除非它是 sizeof 运算符、_Alignof 运算符或 一元 & 运算符,或者是用于初始化数组的字符串文字,是一个具有 type “类型数组”被转换为类型为“指向类型的指针” 的表达式,该表达式指向 到数组对象的初始元素并且不是左值。如果数组对象有 注册存储类,行为未定义。
这很有用,因为数组索引
a[i]
是使用指针算术定义的:*(a+i)
。struct
中,则无法按值传递数组。
接下来,
sentinel
是用作停止标记的元素类型的无效值,例如对于字符串0和指针大多是NULL
。((size_t*)a)[-1]
或类似位置。
哨兵值的选择取决于数组存储的数据类型。对于涉及指针的任何内容,请使用
NULL
,对于浮点数使用 NAN
,例如:
char* strings[] = {"foo", "bar", "baz", NULL};
double doubles[] = {1.0, 2.4, 6.5, NAN};
现在检查数组的结束位置相当于沿着数组行走,直到找到哨兵:
#include <stddef.h> // for NULL
#include <math.h> // for NAN and isnan(…)
size_t count_strings(char** strings) {
size_t num_strings = 0;
while ((*strings)++ != NULL) {
num_strings++;
}
return num_strings;
}
size_t count_doubles(double* doubles) {
...
while (!isnan(doubles++)) {
...
}
}
对于某些数据类型(例如,
int
),查找哨兵更为困难,但您可以选择一个常规值。
您迭代其地址作为第一个参数传入的数组,并通过作为第二个参数传入的数组长度检查范围。
// Or, void f(int *a, int size) as the array decays
// to a pointer when passed into this function
void f(int a[], int size)
{
// It's your own responsibility to make sure you
// don't access the out-of-range elements.
for (int i = 0; i < size; ++i)
{
printf ("%d\n", a[i]);
}
}
// use of f()
int a[10];
// or f(&a[0], sizeof(a) / sizeof(a[0]))
f(a, sizeof(a) / sizeof(a[0]));