2010-03-08 72 views
10

我该如何可靠地获取C风格数组的大小?经常推荐的方法似乎是使用sizeof,但它并不在foo功能,其中x在传递工作:如何可靠地获取C风格数组的大小?

#include <iostream> 

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; 
} 

答案this question建议sizeof但他们不说,它(显然?)如果您传递数组,则不起作用。那么,我必须使用哨兵吗? (我不认为我的foo功能的用户总是可以信任的把一个哨兵在最后。当然,我可以使用std::vector,但我没有得到漂亮的语法速记{1,2,3,4,5}

+1

http://stackoverflow.com/questions/1810083/c-pointers-pointing-to-an-array-of-fixed-size – AnT 2010-03-08 20:44:56

+0

如果你的函数的用户不做文档告诉他们做的事情,那是他们的问题不是你的问题。不可能防止无知的API滥用。 – 2010-03-08 20:52:15

+0

'foo'中的'x'是一个指针,而不是一个数组。见http://stackoverflow.com/questions/232691/how-can-i-get-the-size-of-an-array-from-a-pointer-in-c,http://stackoverflow.com/questions/1975128 /的sizeof-AN-阵列内式C-编程语言。另外,dup:http://stackoverflow.com/questions/37538/c-how-do-i-determine-the-size-of-my-array – outis 2010-03-08 20:53:51

回答

15

在C中,C中的参数实际上只是指针,因此sizeof()将不起作用。您或者需要将尺寸作为另一个参数传递,或者使用标记 - 以最适合您的设计为准。

其他一些选项:

其他一些信息:

  • 对于C++而不是将原料数组指针,你可能希望有参数使用的东西,包装阵列中的类跟踪数组大小并提供以安全方式将数据复制到数组中的方法的模板。像STLSoft's array_proxy templateBoost's boost::array可能会有所帮助。我以前使用过array_proxy模板,效果不错。在使用参数的函数内部,您可以得到类似于操作的std::vector,但函数的调用者可以使用简单的C数组。没有数组的拷贝 - array_proxy模板几乎自动处理数组指针和数组的大小。

  • 宏在C用于确定元素的数量在数组(当的sizeof()可能会帮助 - 也就是说,你不处理一个简单的指针。):Is there a standard function in C that would return the length of an array?

3

您可以传递大小,使用标记或更好地使用std :: vector。虽然标准::载体缺乏初始化列表仍然很容易构建一个向量与一组元素(虽然不是很漂亮)

static const int arr[] = {1,2,3,4,5}; 
vector<int> vec (arr, arr + sizeof(arr)/sizeof(arr[0])); 

性病:: vector类也使得犯错误困难得多,这在黄金中是值得的。另一个好处是所有C++都应该熟悉它,大多数C++应用程序应该使用std :: vector而不是原始C数组。

作为一个快速的注意,C++ 0x中增加了Initializer lists

std::vector<int> v = {1, 2, 3, 4}; 

您还可以使用Boost.Assign做同样的事情,虽然语法是更令人费解的一点。

std::vector<int> v = boost::assign::list_of(1)(2)(3)(4); 

std::vector<int> v; 
v += 1, 2, 3, 4; 
2

C提供此没有本地支持。一旦数组超出其声明的范围,其大小就会丢失。

可以传递数组的大小。如果你总是保持规模,你甚至可以将它们捆绑到一个结构中,尽管这样你会有一些书本费用。

1

这个怎么样?..

template <int N> 
void foo(int (&x)[N]) { 
    std::cerr << N; 
}
+0

-1:这是一个可怕的想法。 – Brian 2010-03-08 21:14:39

+1

@Brian:根据具体情况,这可能也可能不是一个坏主意。你为什么觉得这很可怕? 这是一个好主意,因为如果你传递一个指针,它就不会编译。 如果函数很大并且调用了许多不同的数组大小,它会很糟糕 - 它会生成一堆函数。另一种方法可能是让这个foo转向并调用private/internal foo_internal(int * x,size_t length); 这取决于使用。我发现这个技术对于字符串函数很有用,如果使用不当,它往往会溢出。 没有解释的评论是一个可怕的想法。 – tony 2010-03-08 21:32:49

0

您需要与阵列一起传递的大小,就像它在许多库函数进行,例如strncpy()strncmp()等对不起,这只是它在C :-)中的工作方式。

或者,也可以推出自己的结构类似:

struct array { 
    int* data; 
    int size; 
}; 

,并通过它在你的代码。

如果你想成为更多的C++ -ish,当然你仍然可以使用std::liststd::vector

4

在GNU的libstdc提及的common idiom ++文档是lengthof功能:

template<typename T, unsigned int sz> 
inline unsigned int lengthof(T (&)[sz]) { return sz; } 

你可以使用它作为

int x[] = {1,2,3,4,5}; 
std::cerr << lengthof(x) << std::endl; 

警告:数组有没有decayed into a pointer只有当这会工作。

1

数组表达式将其类型从“T的N元素数组”隐式转换为“指向T的指针”,其值将是数组中第一个元素的地址,除非数组表达式是操作数sizeof或address-of(&)操作符,或者如果数组表达式是用于在声明中初始化另一个数组的字符串文字。简而言之,您不能将数组作为作为数组传递给函数;函数收到的是一个指针值,而不是数组值。

您必须将数组大小作为单独的参数传递。

由于您使用的是C++,因此使用矢量(或其他合适的STL容器)而不是C风格的数组。是的,你失去了方便的简化语法,但折衷不仅仅是值得的。认真。

2

我也同意Corwin的方法非常好。

template <int N> 
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 N> 
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; 
} 

对我来说很有意义:-)

0

由于C++ 11,有一个很方便的方法:

static const int array[] = { 1, 2, 3, 6 }; 
int size = (int)std::distance(std::begin(array), std::end(array))+1;