【C++】函数的形参

fishing-panhttps://blog.csdn.net/u013921430转载请注明出处】

前言

       这些天又在复习C++,温故知新,每次看书都会发现一些之前被自己忽视掉的知识点,所以,学习是不能止步的!

      作为一种编程语言,C++最重要的两个部分就是函数和变量,这两者之间进行沟通便是通过参数传递,而参数传递有很多需要注意的细节,今天就来讲讲参数传递的问题。

      总的来说,参数传递的过程,就是初始化函数形参的过程。

按值传递

      按值传递是最直接也是最容易理解的参数传递方式,其形式如下;

void fun(int x,int y){...表达式;}    //定义;
fun(a,b);                           //调用

      当进行调用的时候,将参数的值通过拷贝赋值给形参,形参的值在函数体内进行各种计算时,并不影响函数外实参的值,形参值的改变与实参无关;

      传值过程是这样的;

int y = b; int x = a;

     下面这个例子就说明了这点;

#include<iostream>

using namespace std;
void swap(int, int);
void main()
{
    int a(5), b(10);
	
    swap(a, b);
    cout <<"a="<< a << " , "<<"b=" << b << endl;
    system("pause");
    return;
}

void swap(int x, int y)
{
    int temp;
    temp = x; x = y; y = temp;
    cout << "按值传参" << endl;
    cout <<"x="<< x << " , " <<"y="<< y<<endl;
}

        虽然a与b的值被传递进入了swap(),在swap内,形参的值进行交换,但是外部a与b的值并没有交换。

        注:形参的建立是自右往左的,也就是先建立y,再建立x,而函数结束时,删除的顺序与之相反。

按地址传递(指针形参)

      按地址传递是用变量的地址初始化形参,这时候的形参是一个指针,其形式如下;

void fun(int* x,int* y){...表达式;}    //定义;
fun(&a,&b);                           //调用;

      在传参过程中,形参初始化的操作如下;

int *y = &b; int *x= &a;

       这时候重新定义swap()函数,会发现a,b的值被修改了,因为,函数通过指针修改了指针指向的对象的值,这就修改了a,b本身。

#include<iostream>

using namespace std;
void swap1(int*, int*);
void main()
{
    int a(5), b(10);
    swap1(&a, &b);
    cout <<"a="<< a << " , "<<"b=" << b << endl;
    system("pause");
    return;
}

void swap1(int* x, int* y)
{
    int temp;
    temp = *x; *x = *y; *y = temp;
    cout << "按地址传参" << endl;
    cout << "*x=" << *x << " , " << "*y=" << *y << endl;
}

按引用传递

      众所周知,对于引用的操作就是对对象本身的操作,引用是被引用对象本身的一个“别名”,按引用传递参数与引用类似,形参成为了实参的一个“别名”,它的形式如下;

void fun(int &x,int &y){...表达式;}    //定义;
fun(a,b);                           //调用;

       形参初始化的操作如下;

int &y = b; int &x= a;

       可以想见,当按引用传值时,在函数中修改形参的值时,实参的值也被修改了,事实也正是如此。

#include<iostream>

using namespace std;
void swap2(int&, int&);
void main()
{
    int a(5), b(10);
	
    swap2(a, b);
    cout <<"a="<< a << " , "<<"b=" << b << endl;

    system("pause");
    return;
}
void swap2(int& x, int& y)
{
     int temp;
     temp = x; x = y; y = temp;
     cout << "按引用传参" << endl;
     cout << "x=" << x << " , " << "y=" << y << endl;
}

优势

避免进行拷贝操作

      虽然在我们的例子中都用的是简单的int类型,但是在实际使用中,常常需要传递很大的容器对象,或者是大的类类型对象,这些时候需要调用拷贝构造函数进行传参,效率低下,通过引用可以很好的避免这一点,大大地节约计算时间和计算资源。

用于返回信息

      我们知道,一个函数一次只能返回一个值,当需要通过函数知道多个变量的信息是,仅仅有返回值是不够的,引用形参为我们提供了很好的渠道,通过引用可以获得函数计算后的各个值,甚至不需要接收函数的返回值。

数组形参

      与普通变量一样,数组也可以作为函数的形参。但是在《【C++】细说C++中的数组之“静态”数组》中我们提到过,数组是不允许被拷贝的,因此我们不能以传值的形式使用数组形参,所以改换成传地址的方式向函数传递数组实参的信息。

      当且仅当用于函数头或者函数原型时,int *arr与int arr[]是含义相同的,他们都意味着arr是一个指针。所以下面三者是等价的;

int* multi(int a[],int m);
int* multi(int *a,int m);
int* multi(int a[10],int m);

       将数组作为形参时,其实是将数组首元素的地址,包含元素的种类,以及元素的数目提交给了函数,有了这些信息后,函数就可以使用数组的信息了。但是,也有一些问题需要注意,当我们有一个数组时,可以获得数组的大小(利用sizeof()函数),但是当它转化成指针后,我们没法获得它的大小,所以常常显示地向函数传递数组的大小;

#include<iostream>
using namespace std;
 
int* multi(int a[], int, int);
void main()
{
    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    
    int *arr1 = multi(arr,10,10);
    cout << arr1[3]<<endl;
    system("pause");
    return;
}
int* multi(int a[],int len,int m)
{
    
    for (int i = 0; i < len;i++)
    {
        a[i] *= m;
    }
    return a;
}

数组引用形参

      变量可以定义成数组的引用,形参也同样可以,   

int* multi(int (&a)[10],int m);
//注:&a两端的括号不能少,因为[]的优先级更高;C++也不允许引用的数组。其次,必须给定数组的大小,这在一定程度上限制了函数的使用。

多维数组作为形参

      与数组一样,多维数组也可以作为形参传递给函数,与一维数组一样,传递的也是数组首元素的地址。因为处理的是数组的数组,所以首元素本身是一个数组,指针指向的是一个数组,因此第二维的数组的大小不能被省略。

int* multi(int (*a)[10],int m);

//注:*a两端的括号不能掉,因为[]的优先级更高如果失去了括号,那么int *a[10]表示的是包含十个int类型指针的数组。而前者表示a是一个指针,指向含有十个元素的数组。

带默认值的形参

      很多情况下都要用到默认值的形参,例如OpenCV中的很多函数都使用了默认形参,这样使得函数更加灵活好用。
当函数提供了形参的默认值,形参就不是必须要从实参获得值,那么在函数调用时,也不是必须提供与形参数一致的实参。
       形参与实参匹配是从左到右的,第一个形参与第一个实参匹配,第二个形参与第二个实参匹配。因此,指定默认值的形参必须放在形参列表的最右侧,或者说,在带默认值的形参的右边,不允许出现无默认值的形参;

int add(int x = 10, int y = 20){...表达式;}

add();
add(a);
add(a, b);

float f1(float a,float b=1,float c,float d=0);    //错误
float f1(float a,float b,float c=1,float d=0);    //正确

      这里也只是简单的列举了一下C++中形参和参数传递的内容,还有很多复杂的内容需要在项目实践中去了解,但是万变不离其宗,这些东西是我们必须掌握的。

已完。。


猜你喜欢

转载自blog.csdn.net/u013921430/article/details/80611600