栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++:数组--作为-->函数参数【数组仅在定义其的域范围内可确定大小】【数组作为函数参数传递后被转换成指针,其大小信息丢失,只剩下数组中第一个元素的信息】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++:数组--作为-->函数参数【数组仅在定义其的域范围内可确定大小】【数组作为函数参数传递后被转换成指针,其大小信息丢失,只剩下数组中第一个元素的信息】

一、一个例子引发的思考
#include

using namespace std;

int GetSize(int data[]) {
    return sizeof(data);
}

int main() {
    int data1[] = {3, 5, 1, 4, 2};
    int size1 = sizeof(data1);
    cout << "size1 = " << size1 << endl;

    int *data2 = data1;
    int size2 = sizeof(data2);
    cout << "size2 = " << size2 << endl;

    int size3 = GetSize(data1);
    cout << "size3 = " << size3 << endl;

    return 0;
}

打印结果:

size1 = 20
size2 = 8
size3 = 8

Process finished with exit code 0
  • data1是一个数组,sizeof(data1)是求数组的大小。这个数组包含5个整数,每个整数占4个字节,因为总共是20个字节。
  • data2声明为指针,尽管它指向了数组data1,对认真指针求sizeof,得到的结果都是8。
  • 在C/C++中,当数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。因此尽管函数GetSize的参数data被声明为数组,但它会退化为指针,size3的结果仍然是8。
二、数组的两个特殊性质 1、不允许拷贝和赋值

不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。

int a[] = {0,1,2};    // 含有三个整数的数组
int s2[] = a;           // 错误:不允许使用一个数组初始化另一个数组
a2 = a;               // 错误:不能把一个数组直接赋值给另一个数组
2、使用数组是通常将其转化成指针

在C++语言中,指针和数组有非常紧密的联系。使用数组的时候编译器一般会把它转换成指针。

通常情况下,使用取地址符(&)来获取指向某个对象的指针,取地址符也可以用于任何对象。数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。因此像其他对象一样,对数组的元素使用取地址符就能的搭配指向该元素的指针:

string nums[] = {"one", "two", "three"};  // 数组元素是string对象
string *p = &nums[0];                     // p指向nums的第一个元素

然而,数组还有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:

string *p2 = nums;                        // 等价于p2 = &nums[0]

在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。

三、数组作为函数形参

数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响。

  • 因为不能拷贝数组,所以我们无法以值传递的方式使用数组参数。
  • 因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。

尽管不能以值传递的方式传毒数组,但是我们可以把形参写成类似数组的形式:

#include

using namespace std;

void print01(int *arr) {
    printf("print01---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
}

void print02(int arr[]) {
    printf("print02---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
}

void print03(int arr[0]) {
    printf("print03---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
}

void print04(int arr[10]) {
    printf("print04---->arr = %d; *arr = %d; arr[0] = %d; arr[1] = %d; arr[2] = %d; arr[3] = %d; arr[4] = %d; arr[5] = %dn", arr, *arr, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
}

int main() {
    int arr[] = {3, 5, 1, 4, 2};
    printf("数组arr的地址 = arr= %d; 数组arr的地址 = &arr= %d; 数组arr的首元素地址 = &arr[0]= %d; arr的首元素 = *arr = %d; arr的首元素 = arr[0] = %dn", arr, &arr, &arr[0], *arr, arr[0]);
    print01(arr);
    print02(arr);
    print03(arr);
    print04(arr);

    return 0;
}

打印结果:

数组arr的地址 = arr= -717228336; 数组arr的地址 = &arr= -717228336; 数组arr的首元素地址 = &arr[0]= -717228336; arr的首元素 = *arr = 3; arr的首元素 = arr[0] = 3
print01---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758
print02---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758
print03---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758
print04---->arr = -717228336; *arr = 3; arr[0] = 3; arr[1] = 5; arr[2] = 1; arr[3] = 4; arr[4] = 2; arr[5] = 32758

Process finished with exit code 0
  • 尽管表现形式不同,但上面的4个函数是等价的:每个函数的唯一形式都是int类型的。当编译器处理对print函数的调用时,只检查传入的参数是否是int类型。

  • 如果我们传给print函数的是一个数组,则实参自动地转换成指向数组首元素的指针,数组的大小对函数的调用没有影响。

  • 和其他使用数组的代码一样,以数组作为形参的函数也必须确保使用数组时不会越界。

1、需要解决C++中关于数组的2个问题
  1. 数组作为函数参数,传值还是传址?
  2. 函数参数中的数组元素个数能否确定?
#include 

using namespace std;

void testArrayArg(int a[]) {
    cout << endl;

    cout << "testArrayArg---->a地址: " << a << endl;
    cout << "testArrayArg---->a大小: " << sizeof(a) << endl;
    cout << "testArrayArg---->a元素数量: " << sizeof(a) / sizeof(a[0]) << endl;

    cout << "将第4个元素的值改变为10。" << endl;
    a[3] = 10;
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};

    cout << "main---->arr地址: " << arr << endl;
    cout << "main---->arr大小: " << sizeof(arr) << endl;
    cout << "main---->arr元素数量: " << sizeof(arr) / sizeof(arr[0]) << endl;

    testArrayArg(arr);

    cout << endl << "第4个元素的值 = " << arr[3] << endl;

    return 0;
}

打印结果:

main---->arr: 0x9b92dff690
main---->arr地址: 0x9b92dff690
main---->arr大小: 20
main---->arr元素数量: 5

testArrayArg---->a地址: 0x9b92dff690
testArrayArg---->a大小: 8
testArrayArg---->a元素数量: 2
将第4个元素的值改变为10。

第4个元素的值 = 10

Process finished with exit code 0

当我们直接将数组arr作为参数调用testArrayArg()时,实参与形参的地址均是0x9b92dff690。并且,在testArrayArg()中将a[3]的值修改为10后,返回main()函数中,a[3]的值也已经改变。这些都说明:

  • C++中数组作为函数参数是传址。
  • 特别需要注意的是,在main()中,数组的大小是可以确定的。
    main---->arr大小: 20
    main---->arr元素数量: 5
    
  • 但数组作为函数参数传递后,其大小信息丢失,只剩下数组中第一个元素的信息。这是因为C++实际上是将数组作为指针来传递,而该指针指向数组的第一个元素。至于后面数组在哪里结束,C++的函数传递机制并不负责。
    testArrayArg---->a大小: 8
    testArrayArg---->a元素数量: 2
    
  • 上面的特性可总结为,数组仅在定义其的域范围内可确定大小。
  • 因此,如果在接受数组参数的函数中访问数组的各个元素,需在定义数组的域范围将数组大小作为另一辅助参数传递。则有另一函数定义如下:
    void testArrayArg2(int a[], int arrayLength)
    {
      cout << endl << "the last element in array is: " << a[arrayLength - 1] << endl;
    
  • 可在main()中这样调用,这样,testArrayArg2()中便可安全地访问数组元素了:
    testArrayArg2(a, sizeof(a) / sizeof(a[0]));
    



参考资料:
详谈C++中数组作为函数参数
C++数组作为函数参数的几个问题
C++数组作为函数参数

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/979793.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号