如何可靠地获得C型arrays的大小?
如何可靠地获得C风格数组的大小? 通常建议的方法似乎是使用sizeof
,但它在foo
函数中不起作用,其中x
被传入:
#include void foo(int x[]) { std::cerr << (sizeof(x) / sizeof(int)); // 2 } int main(){ int x[] = {1,2,3,4,5}; std::cerr << (sizeof(x) / sizeof(int)); // 5 foo(x); return 0; }
这个问题的答案推荐sizeof
但他们并没有说它(显然?)如果你传递数组不起作用。 那么,我是否必须使用哨兵? (我不认为我的foo
函数的用户总是可以信任最后放一个标记。当然,我可以使用std::vector
,但是我没有得到漂亮的速记语法{1,2,3,4,5}
。)
在C数组中,C中的参数实际上只是指针,因此sizeof()
不起作用。 您需要将大小作为另一个参数传递或使用哨兵 – 最适合您的设计。
其他一些选择:
其他一些信息:
-
对于C ++,您可能希望让参数使用将数组包装在类模板中以跟踪数组大小并提供以安全方式将数据复制到数组中的方法,而不是传递原始数组指针。 像STLSoft的array_proxy模板或Boost的boost :: array这样的东西可能会有所帮助。 我之前使用过
array_proxy
模板来获得很好的效果。 在使用参数的函数内部,你得到std::vector
类的操作,但函数的调用者可以使用一个简单的C数组。 没有复制数组 –array_proxy
模板几乎自动地处理数组指针和数组的大小。 -
在C中用于确定数组中元素数量的宏(当sizeof()可能有帮助时 – 即,你没有处理一个简单的指针): C中是否有一个标准函数可以返回长度一个数组?
GNU Libstdc ++文档中提到的一个常见习语是函数的lengthof
:
template inline unsigned int lengthof(T (&)[sz]) { return sz; }
你可以用它
int x[] = {1,2,3,4,5}; std::cerr << lengthof(x) << std::endl;
警告:仅当数组未衰减为指针时才会起作用。
你可以传递大小,使用哨兵甚至更好地使用std :: vector。 尽管std :: vector缺少初始化列表,但仍然可以很容易地构造一个带有一组元素的向量(虽然不是很好)
static const int arr[] = {1,2,3,4,5}; vector vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
std :: vector类也会让错误变得更加困难,这在黄金方面是值得的。 另一个好处是所有C ++应该熟悉它,并且大多数C ++应用程序应该使用std :: vector而不是原始C数组。
快速说明,C ++ 0x添加了初始化列表
std::vector v = {1, 2, 3, 4};
您也可以使用Boost.Assign执行相同的操作,尽管语法有点复杂。
std::vector v = boost::assign::list_of(1)(2)(3)(4);
要么
std::vector v; v += 1, 2, 3, 4;
c没有为此提供本机支持。 一旦数组从其声明的范围中传出,其大小就会丢失。
您可以使用数组传递大小。 如果你总是要保持大小,你甚至可以将它们捆绑到一个结构中,尽管你会有一些预订的开销。
我也同意Corwin的方法非常好。
template void foo(int (&x)[N]) { std::cerr << N; }
我认为没有人给出一个非常好的理由,为什么这不是一个好主意。
例如,在java中,我们可以编写如下内容:
int numbers [] = {1, 2, 3, 4}; for(int i = 0; i < numbers.length(); i++) { System.out.println(numbers[i]+"\n"); }
在C ++中,它会很好而不是说
int numbers [] = {1, 2, 3, 4}; int size = sizeof(numbers)/sizeof(int); for(int i = 0; i < size; i++) { cout << numbers[i] << endl; }
我们可以更进一步走了
template int size(int (&X)[N]) { return N; }
或者,如果这会导致问题,我想你可以明确地写:
template < int N > int size(int (&X)[N]) { int value = (sizeof(X)/sizeof(X[0])); return value; }
然后我们只需要进入主要:
int numbers [] = {1, 2, 3, 4}; for(int i = 0; i < size(numbers); i++) { cout << numbers[i] << endl; }
我感觉合理 :-)
这个怎么样?..
template void foo(int (&x)[N]) { std::cerr << N; }
数组表达式将其类型隐式地从“N元素数组T”转换为“指向T”,其值将是数组中第一个元素的地址,除非数组表达式是sizeof
的操作数或者地址( &
)运算符,或者数组表达式是否用于初始化声明中的另一个数组的字符串文字。 简而言之,您不能将数组作为数组传递给函数; 函数接收的是指针值,而不是数组值。
您必须将数组大小作为单独的参数传递。
由于您使用的是C ++,因此请使用向量(或其他一些合适的STL容器)而不是C样式的数组。 是的,你失去了方便的速记语法,但这种权衡更值得。 认真。
您需要将大小与数组一起传递,就像在许多库函数中完成一样,例如strncpy()
, strncmp()
等。抱歉,这只是它在C :-)中的工作方式。
或者你可以推出自己的结构,如:
struct array { int* data; int size; };
并传递给你的代码。
当然,如果你想要更多的C ++ -ish,你仍然可以使用std::list
或std::vector
。
从c ++ 11开始,有一种非常方便的方法:
static const int array[] = { 1, 2, 3, 6 }; int size = (int)std::distance(std::begin(array), std::end(array))+1;