-
2018-08-03 11:23:08
在C++中,如果函数的实参的类型是数据类型比较大的数据类型,这是如果使用一般传参就会有很大的不方便,这是如果能够传递一个地址或者是对原来参数的一个引用对提高性能会有很大的帮助。
本文研究一下引用传参和指针传参的区别和联系。其实引用传参和指针传参都能够在条用函数内部对源数据进行修改,这是它们的共同点,但是它们也是有区别的。下面是一个例子:
#include <iostream> using namespace std; void SwapByPoint(int* x,int* y); //指针传参函数的声明 void SwapByReference(int &x,int &y); //引用传参函数的声明 int main() { int x = 3; int y = 5; cout<<"转化前: x="<<x<<" y="<<y<<"/n"; SwapByPoint(&x,&y); //如果这里使用 SwapByPoint(x,y) 则报错:cannot convert parameter 1 from 'int' to 'int *' cout<<"指针传参转换后:x="<<x<<" y="<<y<<"/n"; SwapByReference(x,y); //如果这里用SwapByReference(&x,&y) 则报错 cannot convert parameter 1 from 'int *' to 'int &' cout<<"引用传参调用转换后:x="<<x<<" y="<<y<<"/n"; system("pause"); return 0; } /*交换函数 使用指针传参*/ void SwapByPoint(int *x,int *y) { int temp = *x; *x = *y; *y = temp; } /* 使用引用传参 */ void SwapByReference(int &x,int &y) { int temp = x; x = y; y = temp; }
指针传参和引用传参的效果是一样的。
它们的差别个人认为:
Ø 指针传参传递的是一参数(这里是Int实参)的地址,这样,虽然实参和形参不一样,但是它们只想的地址是一样的,所以对相同地址的数的操作会影响到原来的数。
Ø 引用传参传递的是一个参数本身,但是在调用函数中,把保存它们的地址的值做了交换。
两种传参方式的调用必须是上述这样的,否则会报错,在相应的代码中有提示…..
更多相关内容 -
引用传参和指针传参(c++)
2021-06-11 21:22:50引用传参和指针传参因为数据结构的算法设计题要求手写代码,书上函数的形参部分中用到了c++里引用(&)的概念,当时老师只讲了“在形参前面加&符号可以改变传进来的实参的值,如果不熟悉引用也可以用指针传参去改变实参的值”。
现在打算后面统一用引用传参的形式,原因如下:- 教材和各种辅导书都是用的引用传参,方便核对答案;
- 指针传参有两方面缺点:
(1)如果用指针传参的话,需要在函数里重复使用“*指针变量名”的形式来对实参进行操作,容易产生错误且程序的阅读性较差;
(2)在主调函数的调用点处,需要用变量的地址作为实参,而这就导致需要额外定义一个该变量类型的指向该变量的指针;
函数通过指针传参:
int Init_by_pointer(SqList *pL, Elemtype e1, Elemtype e2) { //Initial sequence list L = (e1, e2) by using pointer pL (*pL).base = (Elemtype *)malloc(INIT_LIST_SIZE * sizeof(Elemtype)); if(!(*pL).base) exit(-1); (*pL).length = 2; (*pL).listsize = INIT_LIST_SIZE; (*pL).base[0] = e1; (*pL).base[1] = e2; return 0; }
函数通过引用传参:
int Init_by_reference(SqList &L, Elemtype e1, Elemtype e2) { //Initial sequence list L = (e1, e2) by using reference &L L.base = (Elemtype *)malloc(INIT_LIST_SIZE * sizeof(Elemtype)); if(!L.base) exit(-1); L.length = 2; L.listsize = INIT_LIST_SIZE; L.base[0] = e1; L.base[1] = e2; return 0; }
主函数部分:
#include <stdio.h> #include <stdlib.h> #include <status.h> #define INIT_LIST_SIZE 10 typedef struct SqList { Elemtype *base; int length; int listsize; }SqList; int main(void) { SqList L1; SqList *pL1 = &L1; //额外定义 Init_by_pointer(pL1, 1, 2); printf("L1 = (%d, %d)\n", L1.base[0], L1.base[1]); SqList L2; Init_by_reference(L2, 3, 4); printf("L2 = (%d, %d)\n", L2.base[0], L2.base[1]); return 0; }
结果:显然这两种方式实现的效果是一样的
引用的原理:从编译的角度来讲,在创建符号表的时候,引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)。所以我理解的“引用”实际上就是一个变量的“别名”,所以任何对于引用参数的处理都会通过寻址,操作到主调函数中的相关变量(即实参)。
-
c++ 引用传参和指针传参的区别
2019-05-26 19:32:47指针从本质上讲是一个变量,变量的值是另一个变量的地址,指针在逻辑上是独立的,它可以被改变的,包括指针变量的值(所指向的地址)和指针变量的值对应的内存中的数据(所指向地址中所存放的数据)。 引用从本质上...概念
- 指针从本质上讲是一个变量,变量的值是另一个变量的地址,指针在逻辑上是独立的,它可以被改变的,包括指针变量的值(所指向的地址)和指针变量的值对应的内存中的数据(所指向地址中所存放的数据)。
- 引用从本质上讲是一个别名,是另一个变量的同义词,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化(先有这个变量,这个实物,这个实物才能有别名),而且其引用的对象在其整个生命周期中不能被改变,即自始至终只能依附于同一个变量(初始化的时候代表的是谁的别名,就一直是谁的别名,不能变)。
区别
指针 变量,独立,可变,可空,替身,无类型检查 引用 别名,依赖,不变,非空,本体,有类型检查 -
指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传递的特点是,被调函数对形式参数的任何操作都是作为局部变量进行的,不会影响主调函数的实参变量的值(形参指针变了,实参指针不会变)。
-
引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参(本体)的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量(根据别名找到主调函数中的本体)。因此,被调函数对形参的任何操作都会影响主调函数中的实参变量。
-
引用传递和指针传递是不同的,虽然他们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将应用不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量(地址),那就得使用指向指针的指针或者指针引用。
-
从编译的角度来讲,程序在编译时分别将指针和引用添加到符号表上,符号表中记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)。符号表生成之后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。
以上内容来源网络
如何使用
如果我们编程只是为了做一些简单的工作,不想在技术上有什么质的突破,那么使用指针就够了。这样做的问题就是,你写的代码很容易出bug。可是,如果我们想要对c++有更深的了解,那么一定要区分指针传参与引用传参的区别。
使用指针传递参数,是为了避免拷贝副本,从而提高程序执行效率,大所数初学者(也包括我)都习惯使用指针传递参数,因为还没有建立起引用的概念,我们以为指针就是引用,殊不知,引用的内涵比指针更丰富。因为用的少,所以对引用的概念懵懵懂懂。其实有经验的程序员在传递参数时很少使用指针。下面通过代码来说明我们为什么要使用引用传参,放弃指针传参。
- 首先定义一个结构体
struct ST { public: int num; string name; ST(int num, string name) { this->num = num; this->name = name; } void putInfo() { cout << "学号:" << num << endl; cout << "姓名:" << name << endl; } };
1.使用指针传参
void dealProcess(ST* st) { ST *newST =new ST(320, "小明"); st = newST;//为临时指针变量赋予了新值,已和输入脱离了联系。 } int main() { int num = 1; ST st1(310, "小红"); dealProcess(&st1); st1.putInfo(); system("pause"); return 0; }
- 输出结果
使用指针传参,想返回处理后的结果,但是我们得到的结果却和预想的不一致。因为在处理的过程中,形参的地址发生了变化,和输入脱离了联系。
- 正确的写法:
void dealProcess(ST* st) { ST *newST =new ST(320, "小明"); *st = *newST; }
- 严谨的写法(但不简洁)
void dealProcess(ST* const st)//指定形参为常量指针,不能修改值 { ST *newST =new ST(320, "小明"); *st=*newsT; st = newST; //编译错误,不允许修改常量 }
void dealProcess(ST* const st)
等价于void dealProcess(ST* st const)
2.既严谨又简洁的写法,使用引用
void dealProcess(ST& st) { ST newST(320, "小明"); st = newST; &st=&newsT;//编译错误,不允许改变输入的地址 } int main() { int num = 1; ST st1(310, "小红"); dealProcess(st1); st1.putInfo(); system("pause"); return 0; }
3.如果仅仅是使用输入的值,应该限定输入为常量
- 首选是使用引用
void dealProcess(const ST& st) { ST newST(0,""); newST.putInfo(); //输入的值不允许被改变 st = newST; //编译错误,只允许使用输入,不允许改变输入的值 &st = &newsT;//编译错误,不允许改变输入的地址 //使用输入的值, newST = st; newST.putInfo(); } int main() { int num = 1; ST st1(310, "小红"); dealProcess(st1); system("pause"); return 0; }
- 如果一定要使用指针,等价代码如下
void dealProcess(const ST* const st) { ST newST(0,""); newST.putInfo(); //使用输入的值 newST = *st; newST.putInfo(); } int main() { int num = 1; ST st1(310, "小红"); dealProcess(&st1); system("pause"); return 0; }
-
C++中函数的引用传参和指针传参
2019-11-26 17:33:22按址传递可以通过指针(pointer)和引用(reference)的方式传递,效果相同,但用法不同。 可通过下面冒泡排序的例子来理解: #include <iostream> #include <vector> using namespace std; /*交换两个...参考了Essential C++,
对于函数的形参有两种传参方式,即,按值传递和按址传递;
按址传递可以通过指针(pointer)和引用(reference)的方式传递,效果相同,但用法不同。
可通过下面冒泡排序的例子来理解:#include <iostream> #include <vector> using namespace std; /*交换两个数值*/ void swap (int &val1, int &val2){ int temp; temp = val1; val1 = val2; val2 = temp; } /*通过指针传参*/ void bubble_pass_by_pointer (vector<int> *vec){ for (int i = 0; i < vec->size(); i++){ for (int j = i+1; j < vec->size(); j++){ if ((*vec)[i] > (*vec)[j]) swap((*vec)[i], (*vec)[j]); } } } /*通过引用传参*/ void bubble_pass_by_reference(vector<int> &vec){ for (int i = 0; i < vec.size(); i++){ for (int j = i+1; j < vec.size(); j++){ if (vec[i] > vec[j]) swap(vec[i], vec[j]); } } } void display(vector<int> vec){ for (int i = 0; i < vec.size(); i++){ cout << vec[i] << " "; } cout << endl; } int main(){ int a[10] = {9, 2, 12, 23, 1, 4, 5, 6, 90, 3}; vector<int> vec(a, a+10); //vector<int> *vec_pointer = &vec; //bubble_pass_by_pointer(vec_pointer); bubble_pass_by_reference(vec); display(vec); }
-
值传参,值的引用传参,指针传参(两类),指针的引用传参(两类)
2019-06-29 00:49:101、值传参,对形参的任何操作都不会对实参产生影响 1.1:值传参方法 //值传参 void NoChangeValue(int v) { printf("值传参修改前的值 = %d\n", v); v = 10; printf("值传参修改后的值 = %d\n", v); } 1.2:主... -
指针传参 引用传参 值传参
2021-10-10 20:38:211,指针传参 -> 将变量的地址直接传入函数,函数中可以对其值进行修改。 2,引用传参 -> 将变量的引用传入函数,效果和指针相同。 3,值传参 -> 在传参过程中,首先将c的值复制给函数c变量,然后在函数... -
引用传参和指针传参
2014-09-15 09:18:06指针/引用参数 (2010-12-19 21:36:34) ...在C++中,函数参数主要采用两种传递方式:值传递和引用传递。所谓值传递是指在调用函数时将实际参数复制一份传递到函数中,这样,在函数中如果对参数进行修改,将不会影响到实 -
值传参、指针传参、引用传参
2017-07-02 01:46:253种传参方式:值传参、指针传参、引用传参我们知道传参方式有3种:值传参、指针传参、引用传参。这三种方式书写方式各有不同,接下来,我们简单介绍3种传参方式实现的机制。首先看一个程序:这个程序实现的是交换2个... -
指针与引用传参
2020-08-06 21:01:371.常量指针 const int *p=&a,指针的指向可以改,指针...指针的指向和指针指向的值都不可以改 对于函数参数,例如写一个swap函数 void swap01(int a, int b) { int temp = a; a = b; b = temp; cout << -
函数传参问题(指针传参,值传参,引用传参):
2021-11-27 19:53:57c++ 函数传参问题(指针传参,值传参,引用传参) -
【C++】21.函数传参 传指针和传引用的区别
2021-06-25 16:32:51指针传参 向函数传指针参数时,注意区分指针的指向(地址) 与 指针指向的地址中存放的值的区别: 改变形参指针的指向,实参指针指向不会变,实参指向的地址存放的值也不会变; 改变形参指针指向的地址中存放的值,... -
函数参数中指针传参和引用传参的区别
2021-07-20 19:43:55引用符号&...虽然引用和指针的方式作为传参方式都会保留该函数对传入参数的改变,但这两种方法还是有区别的。这个区别表现在,引用的方式下可以直接使用该参数,而指针的方式通常都需要解引用,或 -
指针的引用传参
2020-08-02 00:30:11因为C语言不支持引用传参,有时候我们想在被调用函数中修改调用函数传进来的参数的地址,并让它在返回后仍然有效,这时候能用到的就是指针的指针。或者说是指针的引用。 #include <stdio.h> #include... -
C/C++三种函数传参方式以及指针与引用小结
2019-12-23 00:04:53(1)传值,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对...(3)传引用,实际是通过指针来实现的,能达到使用的效果如传址,可是使用方式如传值。 说几点建议... -
C语言函数 传参以及指针与引用小结
2019-12-22 23:59:57C语言中函数参数传递的三种方式 (1)传值,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对...(3)传引用,实际是通过指针来实现的,能达到使用的效果如传址... -
指针传递和引用传递
2021-04-21 18:03:41指针传递和引用传递 为了更好的理解指针和引用,下面介绍一下指针传递和引用传递。当指针和引用作为函数的参数是如何传值的呢?指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数... -
【C语言进阶】⑤关于数组传参和指针传参辨析
2022-04-18 21:55:06指针和数组二、一维数组传参三、二维数组传参四、总结 一、数组 1.1.一维数组 int arr1[]={1,2,3,4,5,6,7,8}; 数组名 arr1 一般表示的是首元素的地址,以下两种情况除外: (1)&arr1表示整个数组元素的地址;...