1 /*********************************************************
2 * Desc:参数传递:使用引用传递指针和直接传递指针地址的区别
3 * Author:charley
4 * DateTime:2010-12-7 11:00

02 ***********************************************************/
03 #include <iostream>
04 using namespace std;
05   
06 /*
07 函数声明
08 */
09 void swapByRef(int *&,int *&);
10 void swapByPoi(int *,int *);
11   
12 int main(void)
13 {
14     inti=10;
15     intj=20;
16     int*pi=&i; //pi指向i所在的内存地址
17     int*pj=&j;//pj指向j所在的内存地址
18       
19     //通过引用传递参数,传递的是指针本身
20     cout<<"调用swapByRef()之前:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
21     swapByRef(pi,pj);
22     cout<<"调用swapByRef()之后:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
23       
24     cout<<"**********************"<<endl;
25   
26     //通过指针来传递参数,传递的是指针地址
27     cout<<"调用swapByPoi()之前:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
28     swapByPoi(&i,&j);
29     //或者直接 swapByPoi(pi,pj);
30     cout<<"调用swapByPoi()之后:pi="<<pi<<",*pi="<<*pi<<";pj="<<pj<<",*pj="<<*pj<<endl;
31   
32     getchar();
33     return0;
34 }
35   
36 /*
37 通过引用传递参数:
38 参数为整型指针的引用,
39 引用是指针的一个别名,传递时不需要在内存中分配空间来接收参数
40 参考:swapByRef(int &v1,int &v2)
41 */
42 void swapByRef(int *&v1,int *&v2)
43 {
44     int*temp=v1;//指针赋值,指针执行的地址变化了
45     v1=v2;
46     v2=temp;
47 }
48   
49 /*
50 通过指针来传递参数:
51 参数为整型指针变量
52 内存存需要为形参分配空间来接收传进来的指针地址
53 参考:swapByPoi(int v1,int v2)
54 */
55 void swapByPoi(int *v1,int *v2)
56 {
57     inttemp=*v1; //操作指针指向的内容,指针执行的地址未变化
58     *v1=*v2;
59     *v2=temp;
60 }

执行结果:

从结果可以看出:

1. swapByRef方法是直接交换参数的指针执行的地址,所以指针指向的内容也换了

2. swapByPoi方法只是操作指针指向的内容,指针执行的地址未变化

#include <stdio.h>

void swap(int x,int y)//这是错误的写法
{
int temp;
temp=x;
x=y;
y=temp;
}

int main()
{
int a=5,b=8;
swap(a,b);
printf("%d %d\n",a,b);
return 0;
}

代码很容易理解,就是交换2个变量a和b的值并输出,但是运行后我们发现输出结果不是"8 5"而依旧是"5 8",也就是说交换函数并没有将2个变量的值交换,这是为什么呢?

我们知道,C语言中整型变量的形式参数传递的是值而不是地址,也就是形式参数实际上是复制了实际参数的值进入函数运算的,而被复制的实际参数的值并没有改变。就这段代码来说,就是形参x复制了a的值变成5,形参y复制了b的值变成8,然后在swap函数中进行交换,使得x=8,y=5,但实际上a和b的值并没有被交换,这也就是为什么这段代码并没有实现交换的原因。

那么怎么解决呢?

先前我们说了C语言中整型变量的形式参数传递的是值而不是地址,那么现在我们就让它传递地址,直接交换实际参数的值。

#include <stdio.h>

void swap(int *x,int *y)//使用指针传递地址
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}

int main()
{
int a=5,b=8;
swap(&a,&b);
printf("%d %d\n",a,b);
return 0;
}

我们使用指针变量来进行地址传递,形式参数为变量a和b的地址,swap函数直接交换a和b的地址所指向的值。这里一定注意形式参数传递的是地址而不是值

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

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++){
  a[i] = i;
 }
}

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以确保在函数中该变量不会被修改。

个人认为:其实形参建立的是一个新的地址,只是这地址是实参内容的一个COPY,假如实参为p,形参就为_p;

一个传值的问题”*”与”*”相关推荐

  1. a标签传值到另一个页面_Vue组件传值与通信集合

    Vue的组件化给前端开发带来极大的便利,这种依赖数据来控制Dom的模式,区别于以前的开发控制Dom的开发理念,这也导致了一种情况,在Vue中是单向数据流的,意味着只能从父组件向子组件传值,不允许子组件 ...

  2. 学会使用ant design封装一个锚点组件

    我是歌谣 放弃很容易 但是坚持一定很酷 封装一个锚点组件就是要知道一个父子组件的一个传值 很显然 父亲这边传过去一个数组 然后就可以进行循环遍历得到一个新的数值 这边注意 当我们进行一个map返回值得 ...

  3. asp.net添加自定义用户控件并传值

    创建了一个自定义控件 singleControl.ascx View Code 1 using System; 2 using System.Collections.Generic; 3 using ...

  4. iOS 五种传值方式

    1.属性传值和代理传值 #import <UIKit/UIKit.h> #import "SecondViewController.h" @interface View ...

  5. 超链接把一个值传到多个页面的方法

    现在设计一个传值: 1  a.jsp通过超链接传值到b.jsp; <% String str="lalala"; %><a href="company/ ...

  6. vue组件之间的传值(兄弟间的传值)

    概要:vue组件之间的传值大致有三种:父传子,子传父,还有兄弟之间,今天我们主要来讲兄弟之间的传值.废话不多说,我们直奔主题 vue 组件兄弟间的传值是要通过一个事件总线来实现(可以把事件总线理解为一 ...

  7. 关于微信公众号jsapi支付传值的问题

    刚开始接触微信公众号没有多久,只是做了一些简单的操作,如页面显示,近期,需要做一个微信公众号的支付功能,对于小白的我是很痛苦的,忍着痛,勇敢的往上爬. 首先上网查资料,找demo,之前几天一直没有信心 ...

  8. python如何自定义函数_python基础之函数(自定义函数)

    函数: 函数的定义: 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数. ...

  9. python not函数_python 函数

    1 为什么使用函数 在没有接触函数时,有时候需要将一个功能多次写,如果需要修改其中一个变量,则需要把所有实现该功能的代码一处一处改.不利于代码维护,代码量大了,组织结构也会很不清晰. 所以总结不使用函 ...

最新文章

  1. 华为鸿蒙新概念机,华为P50概念机确认,麒麟芯片+鸿蒙系统,这才是真旗舰!...
  2. 甲方乙方和站在外包中间的你 | 每日趣闻
  3. 四、HTTP响应报文格式
  4. 中文信息匮乏年代,新媒体粉墨登场
  5. 过程声明与同名事件或过程的描述不匹配_多特征结合的倾斜无人机影像匹配方法...
  6. ABAP bit 操作
  7. 基于 Spring 实现管道模式的最佳实践
  8. win10一直卡在自动修复_分享:win10自动修复过程中无法正确启动怎么办?
  9. 计算机网络安全常见问题,计算机网络安全是指什么?
  10. anaconda下载 (清华镜像)
  11. 基于J2EE的门诊挂号收费系统设计与实现.rar(毕业论文+程序源码+数据库文件)
  12. AutoCAD软件应用
  13. python mql4_使用MQL5将OHLC值从Python API集成到MT5
  14. 【机器学习入门】(6) 随机森林算法:原理、实例应用(沉船幸存者预测)附python完整代码和数据集
  15. 节日网页HTML代码 学生网页课程设计期末作业下载 清明节大学生网页设计制作成品下载 DW节日网页作业代码下载
  16. 十年一觉电影梦:李安传
  17. OpenGL中纹理坐标和顶点坐标表示
  18. 妖精的尾巴勇气之旅服务器维护,《妖精的尾巴:勇气之旅》开服活动介绍
  19. 搭建适合自己的DDR3仿真平台
  20. 计算机用户权限完全控制,win10用户权限管理文件夹怎么设置_win10文件夹完全控制权限操作方法...

热门文章

  1. 小兔伴伴家庭动物园AR智能早教产品上市
  2. 容器的综合应用:文本查询程序
  3. BZOJ 1692: [Usaco2007 Dec]队列变换( 贪心 )
  4. 使用Lightbox制作照片条
  5. 值类型 引用类型 堆栈 堆 之 异想
  6. zookeeper watch笔记
  7. 高并发的理解和使用场景-----特意区别和多线程的关系
  8. 【小记】-005--纯CSS实现的小玩意儿
  9. java-servlet
  10. 列表异步线程加载图片