数组传参以及二维数组的动态创建

数组作为参数传参以及二维数组的动态创建

一 普通一维数组的参数传递

一维数组的创建以及参数传递比较简单,小编在这就直接代码演示,不做过多描述

#include <iostream>
#include <cstring>
using namespace std;

//或者是int demo(int arr[], int n) {}
//但若是二维或多维数组传参,没这么简单
int demo(int* arr, int n) {
    printf("demo函数中sizeof(arr) = %d\n", sizeof(arr));
    int ans = 0;
    for (int i = 0; i < n; i++) {
        ans += arr[i];
    }
    return ans;
}

int main() {
    int n;
    scanf("%d", &n);
    int arr[n];
    memset(arr, 0, sizeof(arr));  //将数组初始化为0
    printf("main函数中sizeof(arr) = %d\n", sizeof(arr));  //求数组所占的字节数
    for (int i = 0; i < n; i++) scanf("%d", &arr[i]);  //输入数组元素
    printf("the sum of array = %d\n", demo(arr, n));  //求解数组元素总和
    return 0;
}

对应结果展示如下:
在这里插入图片描述
唯一需要注意的是

  1. main函数和demo函数中的sizeof(arr)不一样。
            这涉及到数组传参部分,其实不论demo函数的函数头部是demo(int *arr, int n)还是demo(int arr[], int n),本质上传递的都是数组的首地址,也就元素a[0]的地址,因此站在demo函数的角度来看,它得到的只是一个指针,而在64操作系统中一个指针所占的字节数为8,因此这就是为什么在demo函数中sizeof(arr) == 8 !(从侧面来看,这就是为什么数组作为参数进行传参时需要额外传递数组的大小,否则的话,可以sizeof(arr)/ sizeof(int)直接获取数组的长度)
            那main函数中呢?sizeof(arr)传进去的不也是一个指针吗?其实这句话是错的!虽然有时我们把数组名称理解为地址,但两者并不等价, 这里的arr应该理解为数组名。
            我们的编译器会利用数组名记录数组的相关属性,其中一个属性就是数组包含元素的个数,那有的小伙伴会问:我们应该什么时候把它理解为地址,又什么时候把它看成数组名呢?
            若表达式中存在数组名,编译会产生一个指针常量,该指针常量恒指向数组首地址,因此我们在表达式中可以把它理解为指针。但有两种情况除外
            (1) sizeof(数组名); 返回数组对应的字节数,而不是对应指针常量所占的字节数
            (2) &数组名; 返回指向数组的指针(数组指针)而不是指向指针常量的指针(二维指针) (这涉及到数组指针的概念,注意区分指针数组以及数组指针,再次强调这里大家有必要追根溯源)

  2. memset()函数初始化数组
            memset()函数初始化数组时,是按照字节进行初始化,因此对于整型数组而言,我们memset()初始化,只可以初始化为0或者是-1(int 占4个字节并且数字在计算机内部都是用补码进行表示的,对0而言每一个字节都是0,所以整体上看自然也是0,-1对应的二进制补码每一个字节每一个比特都是1,因此整体上来说自然是 -1)
            其实不仅仅是memset()函数,mem*()一族的函数都是对于单个字节进行操作:比如memcmp()和memcpy()函数等等。

二 二维数组的参数传递

二维数组作为参数进行传递,为了便于描述我们先进行错误演示,代码如下:

#include <iostream>
#include <cstring>
using namespace std;

int demo(int arr[][], int n, int m) {
    int sum = 0;
    for (i : n) {
        for (j : m) sum += arr[i][j];
    }
    return sum;
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    int arr[n][m];
    memset(arr, 0 ,sizeof(arr));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) scanf("%d", &arr[i][j]);
    }
    printf("the sum of array = %d\n", demo(arr, n, m));
    return 0;
}

此时代码报错,图片如下:
在这里插入图片描述
        错误翻译过来大致意思就是:数组除了第一维度的大小可以省略,剩下的维度均不可以省略
但很显然这不现实,因为数组维度我们预先无法知晓,因此我们只能另想办法,有的小伙伴会说,二维数组数组名不是可以理解为二维指针吗?,我们可以用二维指针来进行,这样就可以躲开维度了!

但是显然还是不行,在这里小编就不再粘贴代码了(冗余太多,仅粘贴错误显示)
在这里插入图片描述
正确代码展示如下:

#include <iostream>
#include <cstring>
using namespace std;

//不可以使用demo(int a[][], int n, int m) {}
//若想使用则除了第一维大小可以省略,剩下的不可以省略
//但此处数组维度预先不可知,因此此处只好强制转换为一维指针
int demo(int *a, int n, int m) {
    int sum = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) sum += *((a + i * m) + j);
    }
    return sum;
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    int arr[n][m];
    memset(arr, 0, sizeof(arr));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) scanf("%d", &arr[i][j]);
    }
    printf("the sum of array = %d\n", demo((int *)arr, n, m));
    return 0;
}

总之:当二维数组作为参数进行传参时,由于数组维度的不可知性,我们不可以用int arr[][]或者int **arr的形式,小编的办法是将其强转为一维指针,通过*运算,完成相应操作;若数组维度预先可知,此时可以使用int arr[][]的形式。

三 动态创建二维数组以及传参

在动态创建二维数组时,我们使用malloc(),free()函数或者是new,delete操作符,动态申请内存空间(是在堆中申请空间,并且申请和释放操作应该成对出现)
话不多说,咱们直接上代码:

#include <iostream>
#include <cstring>
using namespace std;

int demo(int **arr, int n, int m) {
    int sum = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) sum += arr[i][j];
    }
    return sum;
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    printf("开始动态创建二维数组\n");
    int **arr = NULL; 
    arr = (int **)malloc(sizeof(int *) * n);
    for (int i = 0; i < n; i++) {
        arr[i] = (int *)malloc(sizeof(int ) * m);
        memset(arr[i], 0, sizeof(arr[i]));
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0;  j < m; j++) scanf("%d", &arr[i][j]);
    }
    printf("the sum of array = %d\n", demo(arr, n, m));
    for (int i = 0; i < n; i++) free(arr[i]);
    free(arr);
    printf("释放数组空间完毕\n");
    return 0;
}

对应输出为:
在这里插入图片描述
        二维数组数组名我们可以理解为一个二维指针,数组的每一行,我们都有一个行指针,每一行对应m个元素。细心的小伙伴会发现,采用动态创建的二维数组,demo()函数中可以直接使用arr[][],而不需要使用*运算符,此外动态创建的二维数组(在堆中申请空间)相比较于普通创建的二维数组(在栈中申请内存空间)可以开的更大而不用担心出现segment fault段错误,这也是动态创建的另一个优势。
        最后想要提醒大家的一点是,使用完数组后,要free()释放申请的内存空间。

四 题外话

加油,路漫漫其修远兮,吾将上下而求索!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值