C++中引用、指针,传值的联系和区别
2016-03-10 15:49
453 查看
CPU型号:Intel(R) Core(TM) i5-2450M
系统:windows 10
IDE:Microsoft Visual C++ 6.0(下文中简称VC)
制图软件:Photoshop cs5
首先介绍下概念:
原变量:原变量即实参,引用、指针、传值都是指一个函数对应的形参
引用:即pass by reference,引用是某一变量的别名,即引用和被引用的变量的地址为同一个地址,对引用的操作与对变量的操作完全一样(要强调的一点,引用是C++中的概念,在.c中编译是编译不过的)
指针:指针的大小由当前CPU的寻址位数决定的(因此常见为32位即4个字节),指针本身是一个地址,地址里面的值为一个指向内存的存储单元,即一个地址
传值:即pass by value,传值是最简单的传递值的方式,它会在被调用函数中生成一个变量副本,作用范围为该函数体
共同点:三者可以作为传递值来使用,实际上也都是一个地址
不同点:引用和原变量为同一个地址;指针多声明了一个变量(指针本身,局部变量),但是指针的值为原变量;传值也多声明一个变量(传值本身,局部变量)
接下来用代码来说明三者作为函数参数传递时的联系和区别:
执行结果如下:
从红色框部分可以看出,原变量n的地址为0x0019FF3C,值为5。
经过传值调用后,传值的地址为0x0019FEEC,不再是原变量的地址,对传值的值进行改变,并不会对原变量产生影响。
经过指针调用后,指针的地址为0x0019FEEC,其值为0x0019FF3C,值为原变量的地址,而为了改变原变量的值,必须通过加取值符*才能对原变量进行改变。
经过引用调用后,引用的地址为0x0018FF3C,跟原变量为同一个地址,改变引用的值当然可以改变原变量的值。
(传值和指针的地址一样的原因是因为传值和指针都是局部变量,并且是它们的内存空间是由系统中的栈自行申请及释放的,也就是超出作用域就被释放。虽然它们地址相同,但是意义不同,即所占有该地址的时间不同)
由此可以做出结论:
(1)在作为函数参数调用中,引用即省空间又省时间(声明和定义变量需耗费额外的内存和CPU计算时间)
(2)引用本质上就是原变量,只是名字不一样而已,可以直接使用;指针的值才是原变量的地址,该改变原变量的值必须通过取值符*后才能改变
(3)对形参进行sizeof()操作,就会发现传值和引用的大小就是原变量的类型大小,而指针的大小就是指针的大小,不是原变量的类型大小(代码中将原变量的类型定义为short,就是为了和指针的大小区分开来)
如要要做进一步的延伸,就可以讨论指针的特性和地址(引用本质上就是一个地址)的区别:
(4)存在多级指针,但不存在多级引用(多级引用毫无意义,因为引用本身就是个地址,对地址取地址毫无意义)
(5)指针可以指向任何地址,但是引用必须指向用户可使用的内存地址(换句话说就是指针灵活,但是破坏性也大,而引用只能引用已经定义的除了指针变量,数组外的变量,且不能直接对地址引用)
通俗点讲,指针可以指向任何地址,包括NULL,(其实NULL的定义为#define NULL 0),而一般情况下我们把指向NULL的指针理解为空指针,实际上这并不是安全的做法!指针强大但是也很危险!
而引用只能指向已定义的非指针、数组变量的变量,且不能直接对地址进行引用(NULL也算一个地址)。
(6)指针声明时可以不用初始化,引用声明时必须初始化
(7)指针的值可以随意改变,引用一旦定义就无法改变其引用的地址
由结果可知,指针重新指向后可以改变其地址,但是引用就无法做到,地址无法改变。这里可以大胆猜想,引用只有在声明定义的时候才能决定它的地址,之后的操作都只是赋值。
系统:windows 10
IDE:Microsoft Visual C++ 6.0(下文中简称VC)
制图软件:Photoshop cs5
首先介绍下概念:
原变量:原变量即实参,引用、指针、传值都是指一个函数对应的形参
引用:即pass by reference,引用是某一变量的别名,即引用和被引用的变量的地址为同一个地址,对引用的操作与对变量的操作完全一样(要强调的一点,引用是C++中的概念,在.c中编译是编译不过的)
指针:指针的大小由当前CPU的寻址位数决定的(因此常见为32位即4个字节),指针本身是一个地址,地址里面的值为一个指向内存的存储单元,即一个地址
传值:即pass by value,传值是最简单的传递值的方式,它会在被调用函数中生成一个变量副本,作用范围为该函数体
共同点:三者可以作为传递值来使用,实际上也都是一个地址
不同点:引用和原变量为同一个地址;指针多声明了一个变量(指针本身,局部变量),但是指针的值为原变量;传值也多声明一个变量(传值本身,局部变量)
接下来用代码来说明三者作为函数参数传递时的联系和区别:
#include <iostream> using namespace std; void PassByValue(short value) { ++value; cout<<"PassByValue:Addr is 0x"<<&value<<",sizeof(value)="<<sizeof(value)<<",value is "<<value<<endl<<endl; } void PassByPointer(short *value) { ++*value; cout<<"PassByPointer:Addr is 0x"<<&value<<",sizeof(value)="<<sizeof(value)<<",value is "<<value<<",*value="<<*value<<endl<<endl; } void PassByReference(short &value) { value++; cout<<"PassByReference:Addr is 0x"<<&value<<",sizeof(value)="<<sizeof(value)<<",value is "<<value<<endl<<endl; } void main(void) { short n = 5; cout<<"Main:Addr is 0x"<<&n<<",value is "<<n<<endl<<endl; PassByValue(n); cout<<"Main(After PassByValue):Addr is 0x"<<&n<<",value is "<<n<<endl<<endl<<endl; PassByPointer(&n); cout<<"Main(After PassByPointer):Addr is 0x"<<&n<<",value is "<<n<<endl<<endl<<endl; PassByReference(n); cout<<"Main(After PassByReference):Addr is 0x"<<&n<<",value is "<<n<<endl<<endl<<endl; }
执行结果如下:
从红色框部分可以看出,原变量n的地址为0x0019FF3C,值为5。
经过传值调用后,传值的地址为0x0019FEEC,不再是原变量的地址,对传值的值进行改变,并不会对原变量产生影响。
经过指针调用后,指针的地址为0x0019FEEC,其值为0x0019FF3C,值为原变量的地址,而为了改变原变量的值,必须通过加取值符*才能对原变量进行改变。
经过引用调用后,引用的地址为0x0018FF3C,跟原变量为同一个地址,改变引用的值当然可以改变原变量的值。
(传值和指针的地址一样的原因是因为传值和指针都是局部变量,并且是它们的内存空间是由系统中的栈自行申请及释放的,也就是超出作用域就被释放。虽然它们地址相同,但是意义不同,即所占有该地址的时间不同)
由此可以做出结论:
(1)在作为函数参数调用中,引用即省空间又省时间(声明和定义变量需耗费额外的内存和CPU计算时间)
(2)引用本质上就是原变量,只是名字不一样而已,可以直接使用;指针的值才是原变量的地址,该改变原变量的值必须通过取值符*后才能改变
(3)对形参进行sizeof()操作,就会发现传值和引用的大小就是原变量的类型大小,而指针的大小就是指针的大小,不是原变量的类型大小(代码中将原变量的类型定义为short,就是为了和指针的大小区分开来)
如要要做进一步的延伸,就可以讨论指针的特性和地址(引用本质上就是一个地址)的区别:
(4)存在多级指针,但不存在多级引用(多级引用毫无意义,因为引用本身就是个地址,对地址取地址毫无意义)
(5)指针可以指向任何地址,但是引用必须指向用户可使用的内存地址(换句话说就是指针灵活,但是破坏性也大,而引用只能引用已经定义的除了指针变量,数组外的变量,且不能直接对地址引用)
通俗点讲,指针可以指向任何地址,包括NULL,(其实NULL的定义为#define NULL 0),而一般情况下我们把指向NULL的指针理解为空指针,实际上这并不是安全的做法!指针强大但是也很危险!
#include <iostream> using namespace std; void main(void) { int *p=NULL; int *q=(int *)0x00000011; //指向绝对地址0x00000011,需强制转换 // cout<<*p<<endl; cout<<*q<<endl; }编译时不会出错,运行时就完蛋了。
而引用只能指向已定义的非指针、数组变量的变量,且不能直接对地址进行引用(NULL也算一个地址)。
#include <iostream> using namespace std; void main(void) { int a; int *p = &a; // int &q = a; int &q = p; //对指针引用,报错 // int &q = 0x00000011; //对地址引用,报错 }
(6)指针声明时可以不用初始化,引用声明时必须初始化
#include <iostream> using namespace std; void main(void) { int *p; int &q; }运行会报错:
error C2530: 'q' : references must be initialized
(7)指针的值可以随意改变,引用一旦定义就无法改变其引用的地址
#include <iostream> using namespace std; void main(void) { int a = 1, b = 2 ; int *p = &a; int &q = a; cout<<"a addr:"<<&a<<",b addr:"<<&b<<endl<<endl; cout<<"p addr :"<<p<<",value:"<<*p<<endl; p = &b; cout<<"p addr :"<<p<<",value:"<<*p<<endl<<endl; cout<<"q addr :"<<&q<<",value:"<<q<<endl; q = b; cout<<"q addr :"<<&q<<",value:"<<q<<endl; }
由结果可知,指针重新指向后可以改变其地址,但是引用就无法做到,地址无法改变。这里可以大胆猜想,引用只有在声明定义的时候才能决定它的地址,之后的操作都只是赋值。
相关文章推荐
- Python动态类型的学习---引用的理解
- 关于指针的一些事情
- Shell脚本中引用、调用另一个脚本文件的2种方法
- c#窗体传值用法实例详解
- C#简单实现子窗体向父窗体传值的方法
- vbs引用另一个vbs的代码
- C# Pointer指针应用实例简述
- ASP.NET页面间的传值的几种方法
- 关于C语言中参数的传值问题
- C++中引用的使用总结
- C++中引用(&)的用法与应用实例分析
- 关于"引用"的几点说明介绍
- C++智能指针实例详解
- C++指向函数的指针实例解析
- 关于c语言指针的两处小tip分享
- 浅析iterator与指针的区别
- 探讨C++中数组名与指针的用法比较分析
- C++编程指向成员的指针以及this指针的基本使用指南
- 详解C++中的指针、数组指针与函数指针
- C++中字符串以及数组和指针的互相使用讲解