【C++】C++自学旅程(5):指针和引用
学C语言的时候,指针一直是一个让人头大的东西,懂,但是不会用,还好现在慢慢会了,还好C++的指针还是跟C基本相同,还好如此我就只用记一些不同的东西了:)
一、无名变量(动态变量)
可以用new来创建一个无名变量,这种变量没有标识符,如:
int *p = new int;
可以在动态创建的同时指定初始化列表,如:
double *pdouble; pdouble = new double(26.7);
之后这个变量就通过指针来间接访问,如:
cin>>*p; cout<<*p; int c = *p+13; ......
一般情况下,称使用new运算符创建的变量为动态变量,因为这些变量要在程序运行期间动态创建和销毁。
动态创建的变量要动态销毁,用delete关键字,如:
delete p;
酱紫就删除了指针p指向的无名空间。
接下来,谁来告诉我这玩意有什么用?
二、const修饰指针
由前面的学习可以知道,const关键字可定义常量,如
const int a=10;
是不能改变的。当const修饰指针,也是不能改的意思,不过他俩结合会有新的火花:
①指向常量的指针
若把const放在声明变量的最左边,如:
1 int i=0; 2 int j; 3 const int *p = &i; 4 *p = 3; //错误!不能通过p修改所指内容 5 i=2; //可以 6 p=&j;
可以发现,酱,不能再通过p修改所指内容,仅此而已,p所指的东西可以通过别的途径更改,p的指向也可以改。
②指针常量
1 int * const p = &i; 2 p=&j; //错误,指针不能修改指向 3 *p=2; //可以
如果要指针指向固定,且不能通过该指针修改所指值,则这样:
const int * const p = &i;
三、引用
引用就是给一个变量取个别名,如:
int a; int &b = a;
相当于a有了另一个名字b,只是另一个名字,系统并没有分配另外一个空间给b。用引用可以减少空间消耗。
需要注意的有:引用声明时必须指定对哪个变量引用,即必须初始化;别名不能再被引用;不能建立数组的引用,因为数组是元素的集合。
下面用大篇幅来说说引用的应用:
①引用作为函数参数
函数参数传递有三种方式:值传递、地址传递和引用传递。下面来看一个例子程序,来看看引用传递怎么用:
1 //引用作为函数参数的引用传递方式 2 #include<iostream> 3 using namespace std; 4 void fun1(int); 5 void fun2(int&); 6 7 int main() 8 { 9 int a=2; 10 cout<<"实参a的地址是:"<<&a<<endl; 11 12 fun1(a); 13 cout<<"主调函数中a="<<a<<endl; 14 15 fun2(a); 16 cout<<"主调函数中a="<<a<<endl; 17 18 return 0; 19 } 20 21 void fun1(int x) 22 { 23 cout<<"值传递中,形参x的地址是:"<<&x<<endl; 24 x=10; 25 cout<<"在fun1函数内部x="<<x<<endl; 26 } 27 28 void fun2(int& x) 29 { 30 cout<<"引用传递中,形参x的地址是:"<<&x<<endl; 31 x=10; 32 cout<<"在fun2函数内部x="<<x<<endl; 33 }
运行结果如下:
实参a的地址是:0x68feec 值传递中,形参x的地址是:0x68fe90 在fun1函数内部x=10 主调函数中a=2 引用传递中,形参x的地址是:0x68feec 在fun2函数内部x=10 主调函数中a=10
可以发现,fun1没有用引用传递,fun1中定义的局部变量x的地址与实参不同,改变形参的值当然也无法对实参a起到作用。而在fun2中,x并不是新定义的局部变量,而是对实参a的引用,所以fun2中的x就是a,地址也相同,那么对引用量x进行变化,实参当然受影响。
总结一下引用传递的优点或者特点:
-
- 引用传递和指针传递效果一样,被调函数中对引用的操作,实际上就是对实参的操作。
- 使用引用传递,并没有产生实参的副本,而是直接对实参操作,比较节省内容,因此在数据量大时,用引用比一般传递参数的效率和所占空间都好。
- 引用传递较指针来说,优点同样有节省空间,因为指针仍然需要为形参开辟空间,且引用传递在使用起来比指针方便(不用经常使用*或&符号)。
②常引用
如:
const int &b=a;
这样就不能通过引用对值进行变更了,更加安全咯~据说能使用const的情况下尽量使用const,虽然我现在还不能完全理解这样做的苦衷。
③引用作为返回值
要用引用作为返回值类型时,函数得这么定义,如:
int &fun(形参列表)
相信用起来没有什么问题吧!~
但是要注意的是:不能返回局部变量的引用,因为局部变量被灭的,引用就会“无所指”,程序会进入位置状态;);也不能引用new定义的动态变量;可以返回类成员的引用,但最好用const。
之后再继续学吧,好晕啊@~@!
四、动态数组
原来之前学的动态变量 new/delete 语句是用在这里啊!申请动态数组如下:
数据类型 * p = new 数据类型[n]; //其中n可以为变量
相当于p指的是这个空间的收地址,跟数组一样咯,但是可以自由控制n的大小了。用完后删除:
delete []p;
特别注意删除语句的形式:[]p!要加方括号在指针前面。
温馨提示:使用了new,指针p就不要更改了,免得出现错误。
学到这个,突然回忆起了在C语言的malloc/free函数,C++也是有这个函数的。所以new/delete和malloc/free有什么不同呢?好奇搜索了一下,原来这是百度的一个笔试题。。。
《百度笔试题:malloc/free与new/delete的区别》by CSDN hackbuteer1
真是深刻感受到知识都来源于生活,小东西也要注意,说不定哪天就派上了大用场。。。不过,不同点第一条(操作对象不同)现在还看不懂。
五、其他指针复习
①函数指针
指向函数的指针。形如:
int (*p)(int,int,int); p=max;
这样,p就指向max了。圆括号不能少!
②指向指针的指针
指的对象还是指针。
int *p=&x; int **p=&p;
③指针数组
数组元素为指针类型的数据。
int *p[5];
P.S. int *p[5] 和 int (*p)[5] 辨析
前者,p优先与[]结合,所以p是一个指针,指向一个有五个数据的数组。
后者是指针数组,数组元素为指针。
数组中举结了@~@