sizeof 计算问题求解 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JQiue
V2EX    C

sizeof 计算问题求解

  •  1
     
  •   JQiue 2021-07-14 15:40:02 +08:00 3037 次点击
    这是一个创建于 1624 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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     Solana     1634 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 16:20 PVG 00:2 LAX 08:20 JFK 11:20
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86