V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JQiue
V2EX  ›  C

sizeof 计算问题求解

  •  1
     
  •   JQiue · 2021-07-14 15:40:02 +08:00 · 2481 次点击
    这是一个创建于 1232 天前的主题,其中的信息可能已经有所发展或是发生改变。
    void foo(int *arr) {
      printf("%d\n", sizeof arr); // 4
    }
    
    int main(){
      int arr[] = {1, 2, 3, 4, 5};
      printf("%d\n", sizeof arr); // 20
      foo(arr);
    }
    

    对于上述代码的sizeof计算数组字节结果有些不太明白,arr很显然和arr[0]是等效的,为什么在主函数中计算arr的大小等于20(所有元素加起来的字节大小),而作为参数传递给另一个函数时却是4

    26 条回复    2021-07-17 14:29:34 +08:00
    ho121
        1
    ho121  
       2021-07-14 15:55:45 +08:00 via Android
    数组传参后都是指针,指针大小在 32 位环境下是 4,64 位环境下是 8
    JQiue
        2
    JQiue  
    OP
       2021-07-14 15:58:35 +08:00
    @ho121 这个我知道,但是为什么 sizeof 在主函数中却是计算数组的所有元素大小
    qieqie
        3
    qieqie  
       2021-07-14 15:59:15 +08:00
    一个是指针一个是数组,第一个 arr 等效的是&arr[0]
    ipwx
        4
    ipwx  
       2021-07-14 16:16:34 +08:00
    首先,指针和数组不等效。。。楼主你想当然地信仰了一个错误观点。



    sizeof(int*) == 4
    sizeof(int[5]) == 20
    3dwelcome
        5
    3dwelcome  
       2021-07-14 16:17:29 +08:00   ❤️ 1
    @JQiue “但是为什么 sizeof 在主函数中却是计算数组的所有元素大小”

    因为 C/C++是类型推导语言,但是函数参数传递中,会丢失原来的类型。

    你在两个函数里,分别用 typeid(arr).name()打一下类型名称就知道了,两者不一样。
    thinkIn
        6
    thinkIn  
       2021-07-14 16:37:42 +08:00 via iPhone
    sizeof 一般是用 define 定义的,你可以看下原理,很简练
    wudicgi
        7
    wudicgi  
       2021-07-14 16:45:13 +08:00
    "arr 很显然和 arr[0]是等效的"

    当然不是等效的,否则 sizeof(arr) / sizeof(arr[0]) 这种计算元素数量的方法还怎么工作
    hanssx
        8
    hanssx  
       2021-07-14 16:49:03 +08:00
    @3dwelcome 是不是看下汇编代码会比较有帮助?

    楼主你没发现类型变了嘛,实参和形参的类型实际上是不一样的,你说的等效,也需要加上取地址符,而且只是地址这个数值等效。一个变量是有类型和大小的。
    lesismal
        9
    lesismal  
       2021-07-14 17:04:26 +08:00
    《 C 陷阱与缺陷》《 C 专家编程》《 C 和指针》了解一下
    rshun
        10
    rshun  
       2021-07-14 17:06:12 +08:00
    函数参数那个*arr 表示的是数组第一个元素,即 arr[0],所以你在函数内做 sizeof 的时候就是 4
    你在 main 里面的做 sizeof,是数组的所有元素,所以是 4*5=20
    echoechoin
        11
    echoechoin  
       2021-07-14 17:08:40 +08:00
    数组传递到函数中会被转换为指针!!! 所以 sizeof (数组) != sizeof(指针)
    ho121
        12
    ho121  
       2021-07-14 17:10:22 +08:00 via Android
    @JQiue
    主函数中,arr 依然是数组,所以 sizeof 的结果是数组大小。另一方面 arr 也可以作为表达式,它代表的是 arr 数组的首地址。

    函数调用 foo(arr)中的 arr 是作为表达式出现的,所以是指针。sizeof arr 中的 arr 代表数组本身。
    lesismal
        13
    lesismal  
       2021-07-14 17:13:14 +08:00
    国人写的印象中《 C 语言深度解剖》还不错,太久了,记不清了。还有本《狂人 C:程序员入门必备》我没看过,但是当初作者在论坛跟大家 PK 各种 C 问题,很多老伙计一块给提了不少勘误和意见,内容应该能靠谱些吧

    刚还搜到一本日本人的《征服 C 指针》,也没读过,但是以前读过的一些日本作者的技术书籍,感觉都挺不错的
    lesismal
        14
    lesismal  
       2021-07-14 17:16:02 +08:00
    多读几本好书就理解清楚了,C 的细节还挺多呢,这么零散着问,很难系统吸收知识点,建议猛读一下我推荐的那几本书
    OliverDD
        15
    OliverDD  
       2021-07-14 17:52:14 +08:00
    JQiue
        16
    JQiue  
    OP
       2021-07-14 17:57:03 +08:00
    @wudicgi 嗯嗯这个我写错了
    lakehylia
        17
    lakehylia  
       2021-07-14 18:21:09 +08:00
    #include <cstdio>

    void f1(int a[5]) {
    printf("f1 sizeof %zu\n", sizeof(a));
    }

    void f2(int a[]) {
    printf("f2 sizeof %zu\n", sizeof(a));
    }

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

    int main()
    {
    int a[5];
    f1(a);
    f2(a);
    f3(a);
    return 0;
    }

    //======== 运行结果

    f1 sizeof 8
    f2 sizeof 8
    f3 sizeof 8
    lakehylia
        18
    lakehylia  
       2021-07-14 18:29:20 +08:00
    C 中数组不能按值传递的规则。
    但是 c++里面,引用有奇效
    void f4(int(&a)[5]) {
    printf("f4 sizeof %zu\n", sizeof(a)); // f4 sizeof 20
    }
    agagega
        19
    agagega  
       2021-07-14 19:16:08 +08:00 via iPhone
    C 的数组不是指针,只是某些时候可以相互转换
    LnTrx
        20
    LnTrx  
       2021-07-14 19:29:59 +08:00
    在函数里无论是写成数组还是指针,实际上都是指针,数组大小的信息已经丢失了

    https://www.geeksforgeeks.org/why-c-treats-array-parameters-as-pointers/
    wwbfred
        21
    wwbfred  
       2021-07-14 20:00:10 +08:00
    所以不喜欢用 C 数组,只是考题倒是很喜欢考。
    你说它是个类型吧,它又不能传递;你说它不是类型吧,他还有自己的大小。
    这种不一致的表现,放到别的地方,就叫做坑。
    lonewolfakela
        22
    lonewolfakela  
       2021-07-15 09:34:22 +08:00
    @thinkIn 啥,哪家编译器的 sizeof 是用 define 定义的?
    7075
        23
    7075  
       2021-07-15 09:44:52 +08:00   ❤️ 1
    C/C++数组传参,是传指针。在定义处,编译器有保留数组类型及数组长度的信息,所以可以用 sizeof 求长度。传参后参数类型转为指针,你 sizeof 求的是指针的 size 。
    thinkIn
        24
    thinkIn  
       2021-07-15 10:14:25 +08:00 via iPhone
    @lonewolfakela 我表述有误,不过可以看看用宏定义的 sizeof,虽然有限制,但是对理解指针很有好处。可以参看这个讨论 https://stackoverflow.com/questions/14171117/implementation-of-sizeof-operator
    7075
        25
    7075  
       2021-07-16 10:07:09 +08:00
    @3dwelcome 并非总是如此,严格的说 C++是强类型语言,类型必须一致才能通过编译。但标准中也定义了 4 种较为隐晦的类型转换(无需程序员声明),能够在某些情况下满足强类型的检查。数组到指针就是其中一种,原因是因为数组类型很特殊,不光要记录数组长度,还要记录数组保存的元素的 size,这个东西,早期编译器是通过“内情向量”来实现的。 往下面细节就太多了。总之类型发生隐晦的变化。
    JQiue
        26
    JQiue  
    OP
       2021-07-17 14:29:34 +08:00
    @LnTrx 谢谢大佬提供的教程网站
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3438 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 11:07 · PVG 19:07 · LAX 03:07 · JFK 06:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.