提问人:Charles Khunt 提问时间:6/9/2009 更新时间:12/28/2020 访问量:38180
如果传递给函数,则确定数组的大小
determine size of array if passed to function
问:
如果数组被传递给另一个函数(大小未传递),是否可以确定数组的大小?数组的初始化方式类似于 int array[] = { XXX } ..
我知道不可能做sizeof,因为它会返回指针的大小。我问的原因是因为我需要在传递数组的另一个函数中运行一个 for 循环。我尝试了类似的东西:
for( int i = 0; array[i] != NULL; i++) {
........
}
但是我注意到,在数组的末尾,array[i] 有时会包含垃圾值,例如 758433,这不是数组初始化时指定的值。
答:
不,这是不可能的。
一种解决方法:在数组的最后一个值处放置一个特殊值,以便您可以识别它。
评论
如果你不能传递大小,你确实需要在最后有一个可区分的哨兵值(你需要自己把它放在那里——正如你所发现的,你不能相信 C++ 会自动为你做到这一点!没有办法让被调用的函数神奇地神圣化大小,如果它没有被传入并且没有明确、可靠的哨兵在使用。
您可以尝试将空字符附加到数组然后发送它吗?这样,您就可以在循环中检查 \0。\0
如果它在您的控制范围内,请使用 STL 容器(如向量或 deque)而不是数组。
评论
其他答案忽略了 c++ 的一个特性。您可以通过引用传递数组,并使用模板:
template <typename T, int N>
void func(T (&a) [N]) {
for (int i = 0; i < N; ++i) a[i] = T(); // reset all elements
}
然后你可以这样做:
int x[10];
func(x);
但请注意,这仅适用于数组,而不适用于指针。
但是,正如其他答案所指出的那样,使用是更好的选择。std::vector
评论
一个明显的解决方案是使用 STL。如果不可能,最好显式传递数组长度。 对于这种特殊情况,我对使用哨兵值技巧持怀疑态度。它有效 最好使用指针数组,因为 NULL 对于哨兵来说是一个很好的值。跟 整数数组,这并不容易 - 你需要有 一个“神奇”的哨兵值,即 不好。
旁注:如果您的数组被定义和初始化为
int array[] = { X, Y, Z };
在与循环相同的范围内,那么
sizeof(array) 将返回它的实际大小(以字节为单位),而不是指针的大小。您可以获取数组长度为
sizeof(array) / sizeof(array[0])
但是,在一般情况下,如果将数组作为指针,则不能使用此技巧。
您可以在 int 数组中添加一个终止符,然后手动单步执行数组以发现方法中的大小。
#include<iostream>
using namespace std;
int howBigIsBareArray(int arr[]){
int counter = 0;
while (arr[counter] != NULL){
counter++;
}
return counter;
}
int main(){
int a1[6] = {1,2,3,4,5,'\0'};
cout << "SizeOfMyArray: " << howBigIsBareArray(a1);
}
此程序打印:
SizeOfMyArray: 5
这是一个 O(n) 时间复杂度运算,这很糟糕。你永远不应该为了发现一个数组的大小而单步执行一个数组。
评论
实际上 Chucks 列表
for( int i = 0; array[i] != NULL; i++) { ........ }
每次调用前的 sizeof 是浪费的,需要知道你得到了什么。
如果将 NULL 放在数组的末尾,则效果很好。
为什么??在嵌入式设计中,在每个例程中传递 sizeof 使每个调用都非常大,而每个数组的调用都为 NULL。我有一个 2K PIC16F684 芯片,它占用了多达 10% 的芯片,使用 12 次调用和数组传递的 sizeof 进行调用。只有数组和带有 NULLS 的 Chucks 代码,每个数组......我需要 4%。
一个真实的例子。谢谢查克的好电话。
评论
我最初用它来回答另一个问题:当一个函数有一个特定大小的数组参数时,为什么它被一个指针替换?,但只是把它移到了这里,因为它更直接地回答了这个问题。
在 @Richard Corden 的回答和 @sbi 的回答的基础上,这里有一个更大的例子来演示以下原则:
使用对给定大小的数组的引用来强制执行给定函数参数输入数组大小,如下所示:
void foo2(uint8_t (&array)[100]) { printf("sizeof(array) = %lu\n", sizeof(array)); }
和:
通过使用引用给定模板参数大小的输入数组的函数模板,允许任何大小的函数参数输入数组,如下所示:
N
template<size_t N> void foo3(uint8_t (&array)[N]) { printf("sizeof(array) = %lu\n", sizeof(array)); }
请看下面的完整示例:
请注意,这个函数原型根本不知道数组大小!(这里只是对人类用户的视觉提示/提醒,但对编译器没有任何影响!100
void foo(uint8_t array[100]) {}
...此函数原型仅允许固定大小为 100 的输入数组:
void foo2(uint8_t (&array)[100]) {}
...这个函数模板原型允许任何输入大小的数组,并在编译时静态地知道它们的大小(因为这就是模板的工作方式):
template<size_t N>
void foo3(uint8_t (&array)[N]) {}
下面是完整示例:
您可以在此处自行运行:https://onlinegdb.com/rkyL_tcBv。
#include <cstdint>
#include <cstdio>
void foo(uint8_t array[100])
{
// is ALWAYS sizeof(uint8_t*), which is 8!
printf("sizeof(array) = %lu\n", sizeof(array));
}
void foo2(uint8_t (&array)[100])
{
printf("sizeof(array) = %lu\n", sizeof(array));
}
template<size_t N>
void foo3(uint8_t (&array)[N])
{
printf("sizeof(array) = %lu\n", sizeof(array));
}
int main()
{
printf("Hello World\n");
printf("\n");
uint8_t a1[10];
uint8_t a2[11];
uint8_t a3[12];
// Is `sizeof(array) = 8` for all of these!
foo(a1);
foo(a2);
foo(a3);
printf("\n");
// Fails to compile for these 3! Sample error:
// > main.cpp:49:12: error: invalid initialization of reference of type ‘uint8_t (&)[100]
// > {aka unsigned char (&)[100]}’ from expression of type ‘uint8_t [10] {aka unsigned char [10]}’
// > foo2(a1);
// > ^
// foo2(a1);
// foo2(a2);
// foo2(a3);
// ------------------
// Works just fine for this one since the array `a4` has the right length!
// Is `sizeof(array) = 100`
uint8_t a4[100];
foo2(a4);
printf("\n");
foo3(a1);
foo3(a2);
foo3(a3);
foo3(a4);
printf("\n");
return 0;
}
示例输出:
(编译器警告,参考里面的调用):sizeof
foo()
main.cpp:26:49: warning: ‘sizeof’ on array function parameter ‘array’ will return size of ‘uint8_t* {aka unsigned char*}’ [-Wsizeof-array-argument]
main.cpp:23:27: note: declared here
(stdout “标准输出”):
Hello World
sizeof(array) = 8
sizeof(array) = 8
sizeof(array) = 8
sizeof(array) = 100
sizeof(array) = 10
sizeof(array) = 11
sizeof(array) = 12
sizeof(array) = 100
这不应该行吗?至少对于像 Arduino(AVR) c++ 这样的东西。
//rename func foo to foo_ then
#define foo(A) foo_(A, sizeof(A))
void foo_(char a[],int array_size){
...
}
评论