C++ 如何在函数中获取作为参数的数组的长度? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rabbbit
V2EX    C++

C++ 如何在函数中获取作为参数的数组的长度?

  •  
  •   rabbbit 2024-01-28 10:55:18 +08:00 7999 次点击
    这是一个创建于 687 天前的主题,其中的信息可能已经有所发展或是发生改变。

    除了传个长度参数进去还有别的办法吗?

    #include <iostream> using namespace std; void f(int nums[]) { cout << sizeof(nums) << endl; } int main() { int nums[5] = {1,2,3,4,5}; f(nums); return (0); } 
    36 条回复    2024-05-11 13:19:21 +08:00
    marat1ren
        1
    marat1ren  
       2024-01-28 11:01:33 +08:00 via iPhone   1
    用向量,别用数组
    shyrock
        2
    shyrock  
       2024-01-28 11:11:04 +08:00 via iPhone   1
    也可以在数组尾部加入一个约定的结尾符
    rabbbit
        3
    rabbbit  
    OP
       2024-01-28 11:12:00 +08:00
    数组和指针的关系?
    翻了些资料。有人说是一个东西,有人说不是。搞不懂。

    #include <iostream>
    using namespace std;

    int main()
    {
    int nums[5] = { 1,2,3,4,5 };
    int* foo = nums;
    int bar = *foo;
    cout << foo << endl;
    cout << bar << endl; // 1
    cout << bar + 1 << endl; // 2
    }
    rabbbit
        4
    rabbbit  
    OP
       2024-01-28 11:13:51 +08:00
    cout << bar + 1 << endl;
    ->
    cout << *(foo + 1) << endl;
    ripperdev
        5
    ripperdev  
       2024-01-28 11:16:18 +08:00   1
    这种写法的话,在 f 函数里的 nums 数组已经退化成指针了。
    如果是 C++20 标准的话,可以这么写
    ```cpp
    #include <iostream>
    using namespace std;

    void f(auto &&nums)
    {
    cout << std::distance(std::begin(nums), std::end(nums)) << endl;
    }

    int main()
    {
    int nums[5] = { 1,2,3,4,5 };
    f(nums);
    return (0);
    }

    ```
    geelaw
        6
    geelaw  
       2024-01-28 11:21:18 +08:00   5
    void foo(int nums[]) 和 void foo(int *nums) 没啥区别,要同时知道长度的话,用 template <size_t n> void foo(int (&nums)[n])
    ripperdev
        7
    ripperdev  
       2024-01-28 11:21:19 +08:00
    不过仍然建议在 C++里面用 array 或者 vector
    leonshaw
        8
    leonshaw  
       2024-01-28 11:28:32 +08:00 via Android   2
    std::span
    ershierdu
        9
    ershierdu  
       2024-01-28 12:43:14 +08:00   1
    从问题和给的样例来看,OP 应该是刚入门?
    建议先学习一下 STL ,也就是 std::vector 之类的。楼上说的其他方案都更高阶了,可能不是现阶段你需要的
    mainjzb
        10
    mainjzb  
       2024-01-28 13:04:33 +08:00   1
    int nums[] 在 go 里其实是对应的 C++ 的 std::vector 。
    那么 C++为什么没有这么做呢,因为出道太早。很多旧代码已经写成这样了。贸然改动会导致旧代码崩溃。所以只能引入新的名词,导致新人难以理解。
    这就是大家经常抱怨 C++历史包袱太多的表现之一。
    GeruzoniAnsasu
        11
    GeruzoniAnsasu  
       2024-01-28 13:31:04 +08:00   1
    见 #8 的标准方法

    然而这个方法不是用来传你理解的数组的,这个传数组引用的方法几乎都发生在 constexpr / consteval 场景中,传入普通的「静态大小」(而非「编译期计算」) array 会导致实例化出大量一次性代码,严重增加目标可执行文件的冗余



    以你现在刚开始入门的阶段建议先好好啃啃 c++ primer ,以前觉得 primer 上来就是模板库太抽象了,但现代版本的 c++ 确实就是大量依赖模板打造的编译期约束上的。
    GeruzoniAnsasu
        12
    GeruzoniAnsasu  
       2024-01-28 13:31:44 +08:00
    @GeruzoniAnsasu 我看走眼了…… 在说 #6
    manyfreebug
        13
    manyfreebug  
       2024-01-28 13:34:16 +08:00
    在 C++ 中,当数组传递给函数时,数组会退化为指针,因此在函数中使用 sizeof 来获取数组的长度是不准确的。在这种情况下,可以通过传递数组的长度作为额外的参数来解决。

    如果你不想显式传递数组长度,你可以考虑使用 C++ 中的 std::array 或者 std::vector 。这两者都包含了一个成员函数 size(),可以方便地获取数组的长度。

    下面是一个使用` std::array` 的例子:
    ```
    #include <iostream>
    #include <array>

    void f(std::array<int, 5>& nums)
    {
    std::cout << nums.size() << std::endl;
    }

    int main()
    {
    std::array<int, 5> nums = {1, 2, 3, 4, 5};
    f(nums);
    return 0;
    }
    ```

    或者使用 `std::vector:`
    ```
    #include <iostream>
    #include <vector>

    void f(std::vector<int>& nums)
    {
    std::cout << nums.size() << std::endl;
    }

    int main()
    {
    std::vector<int> nums = {1, 2, 3, 4, 5};
    f(nums);
    return 0;
    }
    ```
    这样就可以方便地获取数组的长度而不必显式传递长度参数。
    Hackerl
        14
    Hackerl  
       2024-01-28 13:36:02 +08:00   1
    std::span<int>
    iOCZS
        15
    iOCZS  
       2024-01-28 13:53:35 +08:00   1
    sizeof 能求得静态分配内存的数组的长度,sizeof 不能求得动态分配的内存的大小。
    所以得用 STL 里容器
    yolee599
        16
    yolee599  
       2024-01-28 14:03:17 +08:00 via Android   1
    用 C 语言的方案:
    1. 函数再加一个 length 参数,传参的时候传进去。
    2. 数组最后一个元素加一个特别的值,然后在函数内对数组元素进行遍历计数。

    用 c++ 语言的方案:
    使用 std::vector 。
    roycestevie6761
        17
    roycestevie6761  
       2024-01-28 14:11:58 +08:00   1
    不就是最简单的数组引用传递? C++ Primer 有讲,最基础的模板参数的使用,楼上 geelaw 说的是对的,其他人的回答我看着真是头晕,应该没有一个真正用过 C++写项目的
    mainjzb
        18
    mainjzb  
       2024-01-28 14:53:50 +08:00
    ? 楼上在发言什么叼言论,绝大部分人根本不需要使用模板。
    前面所有人说的基本都没啥问题。
    不用模板=没真正用过 C++写项目
    66666666666
    我也来发表偏激: 正是你们这些模板瞎用的人才导致编译贼慢,建议尽快铲除这些异类。
    littlewing
        19
    littlewing  
       2024-01-28 15:03:42 +08:00
    请使用 std::array 或 std::vector
    imKiva
        20
    imKiva  
       2024-01-28 15:08:55 +08:00
    template <typename T, size_t N>
    size_t length(const T (&array) [N]) {
    return N;
    }
    stcheng
        21
    stcheng  
       2024-01-28 15:34:15 +08:00
    +1 to geelaw's answer
    chendl111
        22
    chendl111  
       2024-01-28 16:11:15 +08:00
    #include <bits/stdc++.h>
    using namespace std;

    template <size_t n>
    size_t get_array_length(int (&nums)[n])
    {
    return n;
    }

    int main() {
    int nums[] = {1, 2, 3, 4, 5};
    size_t length = get_array_length(nums);
    std::cout << "The length of the array is: " << length << std::endl;

    // 打印数组中的所有元素
    for (size_t i = 0; i < length; ++i) {
    std::cout << nums[i] << " ";
    }
    std::cout << std::endl;

    return 0;
    }
    ysc3839
        23
    ysc3839  
       2024-01-28 16:23:22 +08:00 via Android
    @ripperdev 这里可以直接用 std::size 吧?用 std::distance 的话,遇到 std::list 可能会报很复杂的错误吧?
    Droi
        24
    Droi  
       2024-01-28 19:20:29 +08:00
    不确定生成的数据长度可以用向量,确定的话用结构体包裹数组与数组相应的长度。
    方法很多啊,能用库当然是最方便的。
    kirory
        25
    kirory  
       2024-01-28 21:07:34 +08:00
    #include <span>
    #include <iostream>

    void f(std::span<int> arr ){
    std::cout << arr.size() <<"\n";
    }
    int main(){
    int arr[] = {1,2,3};
    f(arr);
    }
    Leonooo13
        26
    Leonooo13  
       2024-01-28 21:32:03 +08:00
    @rabbbit 指针指向数组,指针可以指向一个地址,一般指向数组的首地址,通过移动遍历地址。
    junkun
        27
    junkun  
       2024-01-28 22:48:01 +08:00
    C++20 可以用 std::span 。
    zhuangzhuang1988
        28
    zhuangzhuang1988  
       2024-01-28 22:56:40 +08:00
    直接上 Span
    我在 C#也是用 Span.
    用得好, 可以少写很多代码
    Feep
        29
    Feep  
       2024-01-28 23:10:42 +08:00
    编译器遇到 形参列表里的 T[] 时会进行隐式转换
    参考 https://zh.cppreference.com/w/cpp/language/array
    mingl0280
        30
    mingl0280  
       2024-01-29 03:35:40 +08:00 via Android
    手动狗头。
    你可以在数组前面加个长度嘛,反正就是预留一个 size_t 的位置然后再填数组就好啦,进函数先把头部的长度解出来就行了哈哈哈哈。
    araraloren
        31
    araraloren  
       2024-01-29 09:43:56 +08:00
    @chendl111 There is not need to get length using `get_array_length` in same scope of `nums`. You can just using `sizeof`.
    greycell
        32
    greycell  
       2024-01-29 09:56:50 +08:00
    v2 c++水平不如知乎可还行
    lingxi27
        33
    lingxi27  
       2024-01-29 10:05:07 +08:00
    @greycell 比知乎差得可太远了
    yougotme
        34
    yougotme  
       2024-02-10 14:19:08 +08:00 via iPhone
    没必要简单问题复杂化,加一个大小参数吧,把精力用在能搞钱的地方。
    geelaw
        35
    geelaw  
       2024-03-04 18:24:33 +08:00 via iPhone
    @GeruzoniAnsasu #11 应该这样做可以改进可执行文件大小:

    void foo(int *array, size_t length);

    template <size_t length>
    void foo(int (&array)[length])
    { foo(array, length); }

    最终结果里面 foo 模板的实例应该都会内联从而完全消除。如果要支持实参传递则要实现为 functor……
    xuelang
        36
    xuelang  
       2024-05-11 13:19:21 +08:00
    哈哈,你可以看这篇 C++ 函数可变参实现方法的演进: https://selfboot.cn/2024/05/07/variadic_arguments_in_c++/

    模板里可以拿到参数数量的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2624 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 14:57 PVG 22:57 LAX 06:57 JFK 09:57
    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