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以确保在函数中该变量不会被修改。
(以上转自:http://bbs.ednchina.com/BLOG_ARTICLE_1973915.HTM)
原始代码:
typedef struct __tagPanelResolution
{
__tagPanelResolution()
{
iScreenWidth = 0;
iScreenHeight = 0;
iResolutionIdx = 0;
}
int iScreenWidth ;
int iScreenHeight ;
int iResolutionIdx;
void vGetCurResolution( )
{
if ( iResolutionIdx < 0 )
{
return;
}
switch(iResolutionIdx)
{
case RSF_XGA_60:
iScreenWidth = 1024;
iScreenHeight = 768;
break;
case RSF_1080P:
iScreenWidth = 1920;
iScreenHeight = 1080;
break;
case RSF_WUXGA_CVT:
iScreenWidth = 1920;
iScreenHeight = 1200;
break;
case RSF_XGA_120:
iScreenWidth = 1024; //
iScreenHeight = 768;
break;
case RSF_SXGA:
iScreenWidth = 1280; //
iScreenHeight = 1024;
break;
case RSF_1280_800_60:
iScreenWidth = 1280;
iScreenHeight = 800;
break;
case RSF_720P_60:
iScreenWidth = 1280; //
iScreenHeight = 720;
break;
case RSF_1400_1050:
iScreenWidth = 1400; //
iScreenHeight = 1050;
break;
case RSF_XGA_120_VESA:
iScreenWidth = 1024;
iScreenHeight = 768;
break;
default:
break;
}
}
}PANEL_RESOLUTION;
优化代码:
const REGION_RANGE g_rgnResolutionRegion[9] =
{
//xStart, yStart, Width, Height
{ 0, 0, 1024, 768 },
{ 0, 0, 1920, 1080 },
{ 0, 0, 1920, 1200 },
{ 0, 0, 1024, 768 },
{ 0, 0, 1280, 1024 },
{ 0, 0, 1280, 800 },
{ 0, 0, 1280, 720 },
{ 0, 0, 1400, 1050 },
{ 0, 0, 1024, 768 }
};
typedef struct __tagPanelResolution
{
__tagPanelResolution()
{
iResolutionIdx = 0;
}
int iResolutionIdx;
void vGetCurResolution( int &iCX, int &iCY )
{
if ( iResolutionIdx < 0 )
{
return;
}
iCX = ((REGION_RANGE)g_rgnResolutionRegion[iResolutionIdx]).iWidth();
iCY = ((REGION_RANGE)g_rgnResolutionRegion[iResolutionIdx]).iHeight();
}
}PANEL_RESOLUTION;