【问题标题】:Why isn't the size of an array parameter the same as within main?为什么数组参数的大小与 main 中的大小不同?
【发布时间】:2021-10-31 05:28:35
【问题描述】:

为什么作为参数发送的数组大小与 main 中的不同?

#include <stdio.h>

void PrintSize(int p_someArray[10]);

int main () {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* As expected, 40 */
    PrintSize(myArray);/* Prints 4, not 40 */
}

void PrintSize(int p_someArray[10]){
    printf("%d\n", sizeof(p_someArray));
}

【问题讨论】:

    标签: c arrays function sizeof


    【解决方案1】:

    当您将数组类型传递给函数时,它会隐式转换为指针类型。

    所以,

    void PrintSize(int p_someArray[10]) {
        printf("%zu\n", sizeof(p_someArray));
    }
    

    void PrintSize(int *p_someArray) {
        printf("%zu\n", sizeof(p_someArray));
    }
    

    是等价的。所以你得到的是 sizeof(int*)

    的值

    【讨论】:

    • 在 C++ 中,您可以通过引用函数来传递数组,但在 C 中不能这样做。
    • 您需要将数组的大小作为单独的参数传递。那么数组的大小将是 sizeof(*p_someArray) * length
    • 次要:sizeof 运算符返回类型为 size_t 的对象,因此您应该使用 %zu (C99) 打印它,或者如果使用 %d 则将其转换为 int就像上面在你的printf 电话中一样。
    • 阿洛克的说法是正确的。在 printf(..) 中使用不正确的格式说明符是 UB。
    • @Chris_45:C 没有引用,但在 C 中,您可以通过指向整个数组的指针传递数组,如:void PrintSize(int (*p_someArray)[10])。在函数内部,您可以使用解引用运算符*:sizeof(*p_someArray) 访问数组。这与在 C++ 中使用引用的效果相同。
    【解决方案2】:

    在'C'编程语言中'sizeof()'是运算符,他以字节为单位返回对象的大小。'sizeof()'运算符的参数必须是左值类型(整数,浮点数, struct,array)。因此,如果您想知道数组的大小(以字节为单位),您可以非常简单地完成。只需使用 'sizeof()' 运算符,并为他的参数使用数组名称。例如:

    #include <stdio.h>
    
    main(){
    
     int n[10];
     printf("Size of n is: %d \n", sizeof(n)); 
    
    }
    

    在 32 位系统上的输出将是: n 的大小是:40。因为 32 系统上的整数是 4 字节。在 64x 上是 8 字节。在这种情况下,我们在一个数组中声明了 10 个整数。所以结果是 '10 * sizeof(int)'.

    一些提示:

    如果我们有一个像这样声明的数组'int n[]={1, 2, 3, ...155..};'。 所以我们想知道这个数组中存储了多少元素。 使用这个算法:

    sizeof(name_of_the_array) / sizeof(array_type)

    代码:#include

    main(){

    int n[] = { 1, 2, 3, 44, 6, 7 };
    printf("Number of elements: %d \n", sizeof(n) / sizeof(int));
    return 0;
    

    }

    【讨论】:

    • 欢迎来到 StackOverflow 并感谢您撰写答案。不幸的是,这并没有解决问题,特别是关于局部变量的sizeof(n) 和函数参数的sizeof(arg) 之间的区别,尽管两者似乎都是int[10] 类型。
    【解决方案3】:

    在 C 语言中,当您将数组作为参数传递给函数时,它会自动转换为指针,从一个函数传递另一个函数的数组称为引用调用。这就是被调用函数只接收指向函数第一个元素的指针的原因这就是原因

    fun(int a[]) 类似于 fun(int *a) ;

    所以当你打印数组的大小时,它会打印第一个元素的大小。

    【讨论】:

    • 在 C 中没有“引用调用”。
    • "当你打印数组的大小时,它会打印第一个元素的大小。" 不,它会打印指针的大小。
    【解决方案4】:

    您发现的行为实际上是 C 语言中的一大缺陷。每当您声明一个接受数组参数的函数时,编译器都会忽略您并将参数更改为指针。所以这些声明的行为都和第一个一样:

    void func(int *a)
    void func(int a[])
    void func(int a
    typedef int array_plz[5];
    void func(array_plz a)
    

    a 在所有四种情况下都是指向 int 的指针。如果将数组传递给 func,它将立即衰减为指向其第一个元素的指针。 (在 64 位系统上,64 位指针是 32 位 int 的两倍,因此您的 sizeof 比率返回 2。)

    此规则的唯一目的是保持与不支持将聚合值作为函数参数传递的历史编译器的向后兼容性。

    这并不意味着不可能将数组传递给函数。您可以通过将数组嵌入到结构中来解决这个问题(这基本上是 C++11 的 std::array 的目的):

    struct array_rly {
    int a[5];
    };
    void func(struct array_rly a)
    {
    printf("%zd\n", sizeof(a.a)/sizeof(a.a[0]));  /* prints 5 */
    }
    

    或者通过传递一个指向数组的指针:

    void func(const int (*a)[5])
    {
    printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints 5 */
    }
    

    如果数组大小不是编译时常量,您可以将指针指向数组技术用于 C99 可变长度数组:

    void func(int n, const int (*a)[n])
    {
    printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints n */
    }
    

    【讨论】:

      【解决方案5】:

      在 c++ 中,您可以为此目的通过引用传递数组:

      void foo(int (&array)[10])
      {
          std::cout << sizeof(array) << "\n";
      }
      

      【讨论】:

      • 这对 C 题有什么帮助?
      【解决方案6】:

      它是一个指针,这就是为什么将数组的大小作为第二个参数传递给函数的常见实现

      【讨论】:

        【解决方案7】:

        因此,您需要将数组的长度作为第二个参数传递。当您编写代码时,您都声明了一个常量大小的数组,然后将该数组传递给一个函数,让数组长度常量出现在您的代码中的多个位置是很痛苦的......

        K&R 救援:

        #define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 
        

        所以现在你可以做例如:

        int a[10];
        ...
        myfunction(a, N_ELEMENTS(a));
        

        【讨论】:

        • 如果数组的大小在编码时不可用,而只在运行时可用怎么办?有没有其他方法可以计算数组的大小而无需对其大小进行硬编码?
        • 仅当数组声明为“可见”时,显示的方法才有效。对于所有其他情况,您必须手动传递数组长度。
        【解决方案8】:

        正如其他人所说,当用作函数参数时,数组会衰减为指向其第一个元素的指针。还值得注意的是 sizeof 不计算表达式,并且在与表达式一起使用时不需要括号,因此您的参数实际上根本没有被使用,因此您最好将 sizeof 写入类型而不是值。

        #include <stdio.h>
        
        void PrintSize1 ( int someArray[][10] );
        void PrintSize2 ( int someArray[10] );
        
        int main ()
        {
            int myArray[10];
            printf ( "%d\n", sizeof myArray ); /* as expected 40 */
            printf ( "%d\n", sizeof ( int[10] ) ); /* requires parens */
            PrintSize1 ( 0 ); /* prints 40, does not evaluate 0[0] */
            PrintSize2 ( 0 ); /* prints 40, someArray unused */
        }
        
        void PrintSize1 ( int someArray[][10] )
        {
            printf ( "%d\n", sizeof someArray[0] );
        }
        
        void PrintSize2 ( int someArray[10] )
        {
            printf ( "%d\n", sizeof ( int[10] ) );
        }
        

        【讨论】:

          【解决方案9】:

          您不能将数组传递给函数。

          如果你真的想打印大小,你可以传递一个指向数组的指针,但它根本不是通用的,因为你还需要为函数定义数组大小。

          #include <stdio.h>
          
          void PrintSize(int (*p_anArray)[10]);
          
          int main(void) {
              int myArray[10];
              printf("%d\n", sizeof(myArray)); /* as expected 40 */
              PrintSize(&myArray);/* prints 40 */
          }
          
          void PrintSize(int (*p_anArray)[10]){
              printf("%d\n", (int) sizeof(*p_anArray));
          }
          

          【讨论】:

            【解决方案10】:

            行为是设计使然。

            函数参数声明中的相同语法与局部变量定义中的含义完全不同。

            原因在其他答案中有所描述。

            【讨论】:

              【解决方案11】:

              在 C 语言中,没有方法来确定 未知数组的大小,因此数量需要 以及指向第一个元素的指针。

              【讨论】:

              • 一般来说,您应该始终将数组的大小(元素数量)与数组一起传递给函数,除非您有其他方法来确定其大小(例如,空字符终止符)在char[] 字符串数组的末尾)。
              • 请问什么是“未知数组”?
              【解决方案12】:

              因为数组在作为参数传递时会衰减为指针。这就是 C 的工作方式,尽管您可以通过引用在 C++ 中传递“数组”并克服这个问题。请注意,您可以将不同大小的数组传递给此函数:

               // 10 is superfluous here! You can pass an array of different size!
              void PrintSize(int p_someArray[10]);
              

              【讨论】:

                【解决方案13】:

                数组只是松散的大小。在大多数情况下,数组是指向内存的指针。声明中的大小仅告诉编译器为数组分配多少内存 - 它与类型无关,因此 sizeof() 没有什么可做的。

                【讨论】:

                • 对不起,这个答案具有误导性。数组既不是“松散大小”的,也不是“指向内存的指针”。数组有一个非常精确的大小,数组名称代表指向其第一个元素的指针的位置由 C 标准精确指定。
                猜你喜欢
                • 2017-06-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多