【问题标题】:determine size of array if passed to function如果传递给函数,则确定数组的大小
【发布时间】:2010-11-01 08:46:53
【问题描述】:

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

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

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

但我注意到在数组的近端,array[i] 有时包含像 758433 这样的垃圾值,这不是在数组初始化时指定的值..

【问题讨论】:

标签: c++ arrays null pointers


【解决方案1】:

其他答案忽略了 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 是更好的选择。

【讨论】:

  • +1 这在某种程度上是一种解决方案,但会为每个不同的数组大小创建不同的 func() 符号。也就是说,在不同的地方传递的数组有不同的大小,函数会被实例化很多次。尽管将数组的大小插入到另一个具有实际实现并接收大小的函数的调用中,这可能会有所帮助,可能会将其标记为内联(不是编译器必须遵循您的规则......) template inline void wrapper( T (&a)[N] ) { return func( a, N ); } -- func() 是真正的函数。
  • 当然,我们的目标是使对其进行操作的函数足够小,以至于它可能会被内联。我也喜欢你的包装想法。
  • @Anakhand:应该明确说明模板参数 N,因为它无法推导出:max_(foo);
  • 我刚刚添加了另一个更长的示例,并进行了一些比较,这里:stackoverflow.com/a/64054579/4561887
【解决方案2】:

如果它在您的控制范围内,请使用 STL 容器,例如向量或双端队列,而不是数组。

【讨论】:

  • 同意。如果您不了解矢量,那么现在是学习的好时机!它会让你的生活更轻松。
【解决方案3】:

不,这是不可能的。

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

【讨论】:

  • ... 并准备调试有人将特殊值放在数组中间的情况。换句话说:不要这样做。就像其他人说的那样:枯萎使用定义明确的容器(例如 STL)或将数组的大小与它一起作为函数的其他参数传递
  • 在数组末尾使用特殊值只有一个有用的原因:函数中的可变长度参数。但即使在这种情况下,首选指定输入数组的大小。
  • 如果考虑在数组中保存长度,我会在数组的前面传递这个特殊值(数组的长度),我会增加指针,这样指针[-1] 总是这个长度值。据我所知,此概念由 Microsoft Windows BSTR 在内部使用(请参阅 SysAllocString)。如果使用字符串数组,还有另一种可能的解决方案。数组的结尾由数组末尾的双 NULL 字符确定。
【解决方案4】:

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

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

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

在与你的循环相同的范围内,然后

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

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

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

【讨论】:

    【解决方案5】:

    您可以在 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) 时间复杂度的操作,很糟糕。您永远不应该仅仅为了发现它的大小而遍历一个数组。

    【讨论】:

    • 我确实同意@Eric Leschinski 的观点,但现在每场编码比赛都要求您仅以这种方式编写函数原型。由于 Java 等其他语言,C# 有一种方法来查找大小。我认为阿里的答案是完美的。比如codeyourwayin.topcoder.com/arena他们提到不同语言的原型是一样的。
    • 您只需要确保数组中没有零,因为终止符的计算结果与零相同
    • -1 表示过度概括:“你永远不应该为了发现它的大小而单步遍历一个数组。”绝不?你认为 strlen 是如何工作的?
    • 或者,如果你打算在数组的开头而不是结尾使用这个位置,那将变成 O(1),而不是 O(N)。从逻辑上讲,可以将其与将有关数据包的信息保存在标头中进行比较。
    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        其实Chucks上市

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

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

        如果您在数组末尾放置一个 NULL,效果会很好。

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

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

        【讨论】:

        • sizeof 本身既不浪费时间也不浪费空间,它在编译时进行评估。将它作为附加参数传递确实会使函数调用变大一两条指令,是的,当您只有 2K 内存时,这确实很重要。你知道那是……非典型的吗?
        【解决方案9】:

        我最初将此作为另一个问题的答案:When a function has a specific-size array parameter, why is it replaced with a pointer?,但只是将其移至此处,因为它更直接地回答了这个问题。


        @Richard Corden's answer@sbi's answer 为基础,这里有一个更大的示例来展示以下原则:

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

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

          和:

        2. 允许任意大小的函数参数输入数组,通过使用一个函数template引用给定模板参数大小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 原型允许任何输入大小的数组,并且在编译时静态知道它们的大小(因为这就是模板的工作方式):

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

        示例输出:

        (编译器警告,指的是foo()内部的sizeof调用):

        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   
        

        【讨论】:

          【解决方案10】:

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

          //rename func foo to foo_ then
          #define foo(A) foo_(A, sizeof(A))
          
          void foo_(char a[],int array_size){
          ...
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-12-07
            • 1970-01-01
            • 1970-01-01
            • 2015-04-24
            • 2011-03-04
            • 2014-10-27
            • 1970-01-01
            • 2011-03-14
            相关资源
            最近更新 更多