详谈C++引用&和指针在作为形参时的区别

作者:jingxian 时间:2023-12-13 16:50:49 

int n;

int &m = n;

在C++中,多了一个C语言没有的引用声明符&,如上,m就是n的引用,简单的说m就是n的别名,两者在内存中占同样的位置,不对m开辟新的内存空间,对m的任何操作,对n来说是一样的。

对于引用,有以下三条规则:

(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

假如在一个函数中动态申请内存空间,用指针和用引用作形参会得到不同的结果,如下面的例子:

 


void fun(int* &b){ //用引用做形参
b = (int*)malloc(sizeof(int)*3);

for(int i=0; i<3; i++){
b[i] = i;
}
}

如果在main函数中定义了一个int型的空指针并分别作为实参传入,如下:


int main(){
int *a = NULL;

fun(a);

for(int i=0; i<3; i++){
cout << a[i] << " ";
}
cout << "/n";

return 0;
}

结果用指针的函数会出现内存访问出错,用引用的函数则运行正常并正确输出1 2 3.

这是因为:

1. 指针虽然是地址传递,但实际上也是在函数中又定义了一个新的指针让其与传入的指针指向同一地址。但两个指针本身作为变量在内存中的存放地址是不同的,就是说这是两个不同的变量,只是内容(即所指地址)相同。

2. 在函数中对新定义的指针动态申请内存,但是当函数结束后,申请的内存的生命周期也就结束了,所以当回到主函数时,作为实参的指针地址和内容都没有变化。仍然是个空指针,对其进行访问自然出现了内存读错误了。

假如在main函数中这样写:

int *a = (int*)malloc(sizeof(int)*3);

就不会出现内存读错误了,但是输出结果还是错误的,道理也是一样的。

3. 用引用作为实参传入时,fun函数中的b其实就是主函数中a的别名(或者叫外号),反正就是操作完全相同,地址相同,内容相同的一个变量,所以当fun函数返回时,对b的操作在主函数中对a同样有效。

再看一个例子:


int *a = NULL;

char* b = (char*)a;

int *a = NULL;

char* &b = (char*)a;

这一次是在编译阶段的区别:

用指针可以通过编译,而用引用则不可以,提示类型转换出错。

通过这两个例子可以看出,指针比引用灵活,也更加危险。

摘自『高质量c++编程』

条款一:指针与引用的区别

指针与引用看上去完全不同(指针用操作符'*'和'->',引用使用操作符'.'),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢?

首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。

PS:引用在定义时不可加const,否则编译出错,在形参前面则可以加const以确保在函数中该变量不会被修改。

标签:指针,形参,引用,C++
0
投稿

猜你喜欢

  • Android开发中WebView的简单使用小结

    2022-09-11 00:22:43
  • Android项目实现视频播放器

    2022-10-05 07:53:35
  • 2020JDK1.8安装教程详解(一次就可安装成功)

    2023-11-28 04:08:58
  • Java利用future及时获取多线程运行结果

    2022-02-18 21:57:30
  • 详解使用SSM实现简单工作流系统之实现篇

    2021-10-21 07:49:23
  • Java内部类及其特点的讲解

    2023-06-09 19:39:41
  • Android性能优化之RecyclerView分页加载组件功能详解

    2023-06-04 16:24:14
  • c#实现哈夫曼树算法

    2022-11-24 08:25:02
  • java为什么不建议用equals判断对象相等

    2022-07-14 17:17:39
  • Android中的Selector的用法详解及实例

    2023-11-26 22:17:06
  • Android Intent实现页面跳转的方法示例

    2021-11-08 05:27:22
  • Java读取本地json文件及相应处理方法

    2023-10-16 16:37:34
  • 详细介绍Android-Room数据库的使用

    2022-10-30 09:10:53
  • Spring如何基于aop实现事务控制

    2021-07-21 11:26:06
  • 基于Spring p标签和c标签注入方式

    2023-11-25 22:26:36
  • Android App中ListView仿QQ实现滑动删除效果的要点解析

    2022-11-22 03:05:57
  • java中的String定义的字面量最大长度是多少

    2023-09-01 08:35:31
  • Java 详解Collection集合之ArrayList和HashSet

    2021-09-10 06:27:02
  • mybatis映射和实际类型不一致的问题

    2023-08-13 18:09:06
  • C#实现程序开机启动的方法

    2023-09-23 00:55:20
  • asp之家 软件编程 m.aspxhome.com