C++中数组作为函数参数的注意问题

C++中数组作为函数参数的注意问题

1 问题引入

从《剑指Offer》上的相关问题,下面的输出是什么?

#include<iostream>
using namespace std;

int GetSize(int data[]) {
    return sizeof(data);
}
int main() {
    int data1[] = {1,2,3,4,5};
    int size1 = sizeof(data1);

    int *data2 = data1;
    int size2 = sizeof(data2);

    int size3 = GetSize(data1);

    cout<<size1<<" "<<size2<<" "<<size3<<endl;
    return 0;
}

在这里插入图片描述

  1. data1是一个数组,sizeof(data1)是求数组的大小。这个数组包含5个整数,每个整数占4个字节,因为总共是20个字节。
  2. data2声明为指针,尽管它指向了数组data1,对认真指针求sizeof,得到的结果都是4。
  3. 在C/C++中,当数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。因此尽管函数GetSize的参数data被声明为数组,但它会退化为指针,size3的结果仍然是4

2 两个问题

  1. 数组作为函数参数,传值还是传址?
  2. 函数参数中的数组元素个数能否确定?
#include <iostream>
 
using namespace std;
 
void testArrayArg(int a[])
{
  cout << endl;
 
  cout << "in func..." << endl;
  cout << "array address: " << a << endl;
  cout << "array size: " << sizeof(a) << endl;
  cout << "array element count: " << sizeof(a) / sizeof(a[0]) << endl;
 
  cout << "changing the 4th element's value to 10." << endl;
  a[3] = 10;
}
 
int main()
{
  int a[] = {1, 2, 3, 4, 5};
 
  cout << "in main..." << endl;
  cout << "array address: " << a << endl;
  cout << "array size: " << sizeof(a) << endl;
  cout << "array element count: " << sizeof(a) / sizeof(a[0]) << endl;
 
  testArrayArg(a);
 
  cout << endl << "the 4th element's value: " << a[3] << endl;
 
  return 0;

}

在这里插入图片描述

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

结论:C++中数组作为函数参数是传址
特别注意:
特别需要注意的是,在main()中,数组的大小是可以确定的。

array size: 20
array element count: 5


但作为函数参数传递后,其大小信息丢失,只剩下数组中第一个元素的信息。

array size: 4
array element count: 1

 

原因:这是因为C++实际上是将数组作为指针来传递,而该指针指向数组的第一个元素。至于后面数组在哪里结束,C++的函数传递机制并不负责。

如果在接受数组参数的函数中访问数组的各个元素,需在定义数组的域范围将数组大小作为另一辅助参数传递。

void testArrayArg2(int a[], int arrayLength)

主函数可以这样使用:

testArrayArg2(a, sizeof(a) / sizeof(a[0]));

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

3 数组的特性

3.1 不允许拷贝和赋值

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

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

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

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

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

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

string *p2 = nums;                        // 等价于p2 = &nums[0]
结论: 在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。

4 数组形参

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

//尽管形式不同,但这三个print函数是等价的
//每个函数都有一个const int*类型的形参
void print(const int*);
void print(const int[]);
//这里的维度表示我们期望数组含有多少元素,实际不一定
void print(const int[10]); 

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

int i=0,j[2] = {0,1};
print(&i);               //正确:&i的类型是int*
print(j);                 //正确:j转船成int* 并指向j[0]

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

5 数组的引用作为函数参数

#include <iostream>

using namespace std;
//  必须要有5才不报错
void func(int (&a)[5]) {
	for (int i = 0; i < 5; i++) {
        a[i] = 0;
		cout << a[i] << " ";
	}
	cout<<endl;
}
void func1(int a[]) {
	for (int i = 0; i < 5; i++) {
        a[i] = 1;
		cout << a[i] << " ";
	}
	cout<<endl;
}

int main() {
	int number[5] = { 0,1,2,3,4 };
	func(number);
	func1(number);
	cout<<"修改之后";
	for (int i = 0; i < 5; i++) {

		cout << number[i] << " ";
	}
}

在这里插入图片描述
从结果来看,正常传递和引用传递都是可以进行的数值修改的,暂时不明白应用起来有啥不一样的

数组的引用作为函数参数必须要指明大小(代码示例的5必须要有的)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值