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

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

  •  
  •   rabbbit · 300 天前 · 5759 次点击
    这是一个创建于 300 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    #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  
       300 天前 via iPhone   ❤️ 1
    用向量,别用数组
    shyrock
        2
    shyrock  
       300 天前 via iPhone   ❤️ 1
    也可以在数组尾部加入一个约定的结尾符
    rabbbit
        3
    rabbbit  
    OP
       300 天前
    数组和指针的关系?
    翻了些资料。有人说是一个东西,有人说不是。搞不懂。

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

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



    以你现在刚开始入门的阶段建议先好好啃啃 c++ primer ,以前觉得 primer 上来就是模板库太抽象了,但现代版本的 c++ 确实就是大量依赖模板打造的编译期约束上的。
    GeruzoniAnsasu
        12
    GeruzoniAnsasu  
       300 天前
    @GeruzoniAnsasu 我看走眼了…… 在说 #6
    manyfreebug
        13
    manyfreebug  
       300 天前
    在 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  
       300 天前   ❤️ 1
    std::span<int>
    iOCZS
        15
    iOCZS  
       300 天前   ❤️ 1
    sizeof 能求得静态分配内存的数组的长度,sizeof 不能求得动态分配的内存的大小。
    所以得用 STL 里容器
    yolee599
        16
    yolee599  
       300 天前 via Android   ❤️ 1
    用 C 语言的方案:
    1. 函数再加一个 length 参数,传参的时候传进去。
    2. 数组最后一个元素加一个特别的值,然后在函数内对数组元素进行遍历计数。

    用 c++ 语言的方案:
    使用 std::vector 。
    roycestevie6761
        17
    roycestevie6761  
       300 天前   ❤️ 1
    不就是最简单的数组引用传递? C++ Primer 有讲,最基础的模板参数的使用,楼上 geelaw 说的是对的,其他人的回答我看着真是头晕,应该没有一个真正用过 C++写项目的
    mainjzb
        18
    mainjzb  
       300 天前
    ? 楼上在发言什么叼言论,绝大部分人根本不需要使用模板。
    前面所有人说的基本都没啥问题。
    不用模板=没真正用过 C++写项目
    66666666666
    我也来发表偏激: 正是你们这些模板瞎用的人才导致编译贼慢,建议尽快铲除这些异类。
    littlewing
        19
    littlewing  
       300 天前
    请使用 std::array 或 std::vector
    imKiva
        20
    imKiva  
       300 天前
    template <typename T, size_t N>
    size_t length(const T (&array) [N]) {
    return N;
    }
    stcheng
        21
    stcheng  
       300 天前
    +1 to geelaw's answer
    chendl111
        22
    chendl111  
       300 天前
    #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  
       300 天前 via Android
    @ripperdev 这里可以直接用 std::size 吧?用 std::distance 的话,遇到 std::list 可能会报很复杂的错误吧?
    Droi
        24
    Droi  
       300 天前
    不确定生成的数据长度可以用向量,确定的话用结构体包裹数组与数组相应的长度。
    方法很多啊,能用库当然是最方便的。
    kirory
        25
    kirory  
       300 天前
    #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  
       300 天前
    @rabbbit 指针指向数组,指针可以指向一个地址,一般指向数组的首地址,通过移动遍历地址。
    junkun
        27
    junkun  
       300 天前
    C++20 可以用 std::span 。
    zhuangzhuang1988
        28
    zhuangzhuang1988  
       300 天前
    直接上 Span
    我在 C#也是用 Span.
    用得好, 可以少写很多代码
    Feep
        29
    Feep  
       300 天前
    编译器遇到 形参列表里的 T[] 时会进行隐式转换
    参考 https://zh.cppreference.com/w/cpp/language/array
    mingl0280
        30
    mingl0280  
       300 天前 via Android
    手动狗头。
    你可以在数组前面加个长度嘛,反正就是预留一个 size_t 的位置然后再填数组就好啦,进函数先把头部的长度解出来就行了哈哈哈哈。
    araraloren
        31
    araraloren  
       299 天前
    @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  
       299 天前
    v2 c++水平不如知乎可还行
    lingxi27
        33
    lingxi27  
       299 天前
    @greycell 比知乎差得可太远了
    yougotme
        34
    yougotme  
       287 天前 via iPhone
    没必要简单问题复杂化,加一个大小参数吧,把精力用在能搞钱的地方。
    geelaw
        35
    geelaw  
       264 天前 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  
       196 天前
    哈哈,你可以看这篇 C++ 函数可变参实现方法的演进: https://selfboot.cn/2024/05/07/variadic_arguments_in_c++/

    模板里可以拿到参数数量的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   937 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 21:18 · PVG 05:18 · LAX 13:18 · JFK 16:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.