• 数组不可以复制,导致了数组同样不支持传参


    我们知道,结构体类型是可以很轻松的复制的,比如说:

    1. struct St {
    2. int m1;
    3. double m2;
    4. };
    5. void demo() {
    6. St st1;
    7. St st2 = st1; // OK
    8. St st3;
    9. st1 = st3; // OK
    10. }

    但数组却并不可以,比如:

    1. int arr1[5];
    2. int arr2[5] = arr1; // ERR

    明明这里 arr2 和 arr1 同为 int [5] 类型,但是并不支持复制。照理说,数组应当比结构体更加适合复制场景,因为需求是很明确的,就是元素按位复制。

    • 数组类型传参

    由于数组不可以复制,导致了数组同样不支持传参,因此我们只能采用 “首地址 + 长度” 的方式来传递数组:

    1. void f1(int *arr, size_t size) {}
    2. void demo() {
    3. int arr[5];
    4. f1(arr, 5);
    5. }

    而为了方便程序员进行这种方式的传参,C 又做了额外的 2 件事:

    • 提供一种隐式类型转换,支持将数组类型转换为首元素指针类型(比如说这里 arr 是 int [5] 类型,传参时自动转换为 int * 类型)

    • 函数参数的语法糖,如果在函数参数写数组类型,那么会自动转换成元素指针类型,比如说下面这几种写法都完全等价:

    1. void f(int *arr);
    2. void f(int arr[]);
    3. void f(int arr[5]);
    4. void f(int arr[100]);

    所以这里非常容易误导人的就在这个语法糖中,无论中括号里写多少,或者不写,这个值都是会被忽略的,要想知道数组的边界,你就必须要通过额外的参数来传递。

    但通过参数传递这是一种软约束,你无法保证调用者传的就是数组元素个数,这里的危害详见后面 “指针偏移” 的章节。

    • 分析和思考

    之所以 C 的数组会出现这种奇怪现象,我猜测,作者考虑的是数组的实际使用场景,是经常会进行切段截取的,也就是说,一个数组类型并不总是完全整体使用,我们可能更多时候用的是其中的一段。举个简单的例子,如果数组是整体复制、传递的话,做数组排序递归的时候会不会很尴尬?首先,排序函数的参数难以书写,因为要指定数组个数,我们总不能针对于 1,2,3,4,5,6,... 元素个数的数组都分别写一个排序函数吧?其次,如果取子数组就会复制出一个新数组的话,也就不能对原数组进行排序了。

    所以综合考虑,干脆这里就不支持复制,强迫程序员使用指针 + 长度这种方式来操作数组,反而更加符合数组的实际使用场景。

    当然了,在 C++ 中有了引用语法,我们还是可以把数组类型进行传递的,比

    如:

    1. void f1(int (&arr)[5]); // 必须传int[5]类型
    2. void demo() {
    3. int arr1[5];
    4. int arr2[8];
    5. f1(arr1); // OK
    6. f1(arr2); // ERR
    7. }

    但绝大多数的场景似乎都不会这样去用。一些新兴语言(比如说 Go)就注意到了这一点,因此将其进行了区分。在 Go 语言中,区分了 “数组” 和 “切片” 的概念,数组就是长度固定的,整体来传递;而切片则类似于首地址 + 长度的方式传递(只不过没有单独用参数,而是用 len 函数来获取)

    1. func f1(arr [5]int) {
    2. }
    3. func f2(arr []int) {
    4. }

    上面例子里,f1 就必须传递长度是 5 的数组类型,而 f2 则可以传递任意长度的切片类型。

    而 C++ 其实也注意到了这一点,但由于兼容问题,它只能通过 STL 提供容器的方式来解决,std::array 就是定长数组,而 std::vector 就是变长数组,跟上述 Go 语言中的数组和切片的概念是基本类似的。这也是 C++ 中更加推荐使用 vector 而不是 C 风格数组的原因。

  • 相关阅读:
    使用 PyAudio、语音识别、pyttsx3 和 SerpApi 构建简单的基于 CLI 的语音助手
    图形/多段线内缩外扩思路
    2023/09/22 制作demo期间心得
    云计算如何助力夯实制造业“底盘”?材料科学领域专家学者分享新材料前沿技术成果
    超实用6款AI工具,一般人我不告诉他
    TS:知识补充
    计算机网络:运输层
    Opencv项目——信用卡数字识别Python代码实现
    健康防猝指南1:体重和减肥的秘密
    BeanFactory和FactoryBean区别(附BeanFactory和ApplicationContext的区别)
  • 原文地址:https://blog.csdn.net/feidododekefu/article/details/127982071