如果传递给函数,则确定数组的大小

determine size of array if passed to function

提问人:Charles Khunt 提问时间:6/9/2009 更新时间:12/28/2020 访问量:38180

问:

如果数组被传递给另一个函数(大小未传递),是否可以确定数组的大小?数组的初始化方式类似于 int array[] = { XXX } ..

我知道不可能做sizeof,因为它会返回指针的大小。我问的原因是因为我需要在传递数组的另一个函数中运行一个 for 循环。我尝试了类似的东西:

for( int i = 0; array[i] != NULL; i++) {
........
}

但是我注意到,在数组的末尾,array[i] 有时会包含垃圾值,例如 758433,这不是数组初始化时指定的值。

C++ 数组 null 指针

评论

0赞 Gabriel Staples 9/25/2020
相关问题,其中还包含如何执行此操作的演示:当函数具有特定大小的数组参数时,为什么要将其替换为指针?

答:

9赞 tekBlues 6/9/2009 #1

不,这是不可能的。

一种解决方法:在数组的最后一个值处放置一个特殊值,以便您可以识别它。

评论

17赞 Rom 6/9/2009
...并准备好调试当有人将该特殊值放在数组中间的情况时。换句话说:不要这样做。就像其他人说的:使用定义良好的容器(例如 STL)或将数组的大小作为函数的其他参数一起传递
1赞 zabulus 6/24/2011
在数组末尾使用特殊值只有一个有用的原因:函数中的可变长度参数。但即使在这种情况下,指定输入数组的大小也是首选。
0赞 bkausbk 7/22/2013
如果考虑将长度保存在数组中,我会在数组的前面传递这个特殊值(数组的长度),并且我会递增指针,使 pointer[-1] 始终是这个长度值。据我所知,Microsoft Windows BSTR 内部使用这个概念(请参阅 SysAllocString)。如果使用字符串数组,还有另一种可能的解决方案。数组末尾使用数组末尾的双 NULL 字符确定。
3赞 Alex Martelli 6/9/2009 #2

如果你不能传递大小,你确实需要在最后有一个可区分的哨兵值(你需要自己把它放在那里——正如你所发现的,你不能相信 C++ 会自动为你做到这一点!没有办法让被调用的函数神奇地神圣化大小,如果它没有被传入并且没有明确、可靠的哨兵在使用。

1赞 Alan Haggai Alavi 6/9/2009 #3

您可以尝试将空字符附加到数组然后发送它吗?这样,您就可以在循环中检查 \0。\0

15赞 Fred Larson 6/9/2009 #4

如果它在您的控制范围内,请使用 STL 容器(如向量或 deque)而不是数组。

评论

1赞 rlbond 6/9/2009
同意。如果您不了解 vector,现在是学习的好时机!它会让你的生活更轻松。
64赞 Evan Teran 6/9/2009 #5

其他答案忽略了 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

评论

12赞 David Rodríguez - dribeas 6/9/2009
+1 这在某种程度上是一个解决方案,但会为每个不同的数组大小创建一个不同的 func() 符号。也就是说,在不同的地方,传递的数组具有不同的大小,该函数将被实例化多次。不过,在对另一个具有实际实现并接收大小的函数的调用中插入数组的大小可能会有所帮助,可能会将其标记为内联(并不是说编译器必须遵循您的规则...... template<typename T, size_t N> 内联 void 包装器( T (&a)[N] ) { return func( a, N );} -- func() 是真正的函数。
1赞 Evan Teran 6/9/2009
当然,目标是使在其上运行的函数足够小,以便它可能会被内联。我也喜欢你的包装器想法。
1赞 jimifiki 10/11/2019
@Anakhand:应该明确说明模板参数 N,因为它无法推导:max_<int, 2>(foo);
0赞 Gabriel Staples 9/25/2020
我刚刚在这里添加了另一个更长的例子,并进行了一些比较:stackoverflow.com/a/64054579/4561887
7赞 Igor Krivokon 6/9/2009 #6

一个明显的解决方案是使用 STL。如果不可能,最好显式传递数组长度。 对于这种特殊情况,我对使用哨兵值技巧持怀疑态度。它有效 最好使用指针数组,因为 NULL 对于哨兵来说是一个很好的值。跟 整数数组,这并不容易 - 你需要有 一个“神奇”的哨兵值,即 不好。

旁注:如果您的数组被定义和初始化为

 int array[] = { X, Y, Z };

在与循环相同的范围内,那么

sizeof(array) 将返回它的实际大小(以字节为单位),而不是指针的大小。您可以获取数组长度为

sizeof(array) / sizeof(array[0])

但是,在一般情况下,如果将数组作为指针,则不能使用此技巧。

4赞 Ali 7/22/2013 #7

您可以在 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) 时间复杂度运算,这很糟糕。你永远不应该为了发现一个数组的大小而单步执行一个数组。

评论

0赞 siddhusingh 10/25/2014
我确实同意 @Eric Leschinski 的观点,但现在每天每次编码竞赛都要求你只以这种方式编写函数原型。由于其他语言如Java,C#有一种方法来找到大小。我认为阿里的回答是完美的。例如,codeyourwayin.topcoder.com/arena 他们提到不同语言的原型是相同的。
0赞 Nav 4/30/2015
您只需要确保数组中没有零,因为终止符的计算结果与零相同
1赞 Spike0xff 6/22/2016
-1 表示过度泛化:“你永远不应该为了发现它的大小而单步执行数组。从不?你认为strlen是如何工作的?
0赞 Anthony Pace 2/2/2020
或者,如果你打算在数组的开头而不是结尾使用这个位置的计数,这将变成 O(1),而不是 O(N)。从逻辑上讲,它可以与将有关数据包的信息保留在标头中进行比较。
1赞 Saturn5tony 1/5/2014 #8

实际上 Chucks 列表

for( int i = 0; array[i] != NULL; i++) { ........ }

每次调用前的 sizeof 是浪费的,需要知道你得到了什么。

如果将 NULL 放在数组的末尾,则效果很好。

为什么??在嵌入式设计中,在每个例程中传递 sizeof 使每个调用都非常大,而每个数组的调用都为 NULL。我有一个 2K PIC16F684 芯片,它占用了多达 10% 的芯片,使用 12 次调用和数组传递的 sizeof 进行调用。只有数组和带有 NULLS 的 Chucks 代码,每个数组......我需要 4%。

一个真实的例子。谢谢查克的好电话。

评论

2赞 Spike0xff 6/22/2016
sizeof 本身既不浪费时间也不浪费空间,它是在编译时计算的。将它作为附加参数传递确实会使函数调用变大一两条指令,是的,当您只有 2K 内存时,这确实很重要。你意识到那是......典型?
1赞 Gabriel Staples 9/25/2020 #9

我最初用它来回答另一个问题:当一个函数有一个特定大小的数组参数时,为什么它被一个指针替换?,但只是把它移到了这里,因为它更直接地回答了这个问题。


@Richard Corden 的回答@sbi 的回答的基础上,这里有一个更大的例子来演示以下原则:

  1. 使用对给定大小的数组的引用来强制执行给定函数参数输入数组大小,如下所示:

     void foo2(uint8_t (&array)[100]) 
     {
         printf("sizeof(array) = %lu\n", sizeof(array)); 
     }
    

    和:

  2. 通过使用引用给定模板参数大小的输入数组的函数模板,允许任何大小的函数参数输入数组,如下所示: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;
}

示例输出:

(编译器警告,参考里面的调用):sizeoffoo()

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   
0赞 Joseph Chamness 12/28/2020 #10

这不应该行吗?至少对于像 Arduino(AVR) c++ 这样的东西。

//rename func foo to foo_ then
#define foo(A) foo_(A, sizeof(A))

void foo_(char a[],int array_size){
...
}