C++基础7:指针和引用

一.指针

** 1.指针概念**:指针就是用来保存内存地址的变量。

2.声明指针的方式int *p;与运算符*结合,p就表示一个指针

为什么使用指针(指针的三大作用):由于指针可以通过内存地址直接访问数据,可避免在程序中复制大量的代码,因此指针的效率最高,其三大作用如下

2.1 处理堆中存放的大型数据
2.2 快速访问类的成员数据和函数
2.3 以别名的方式向函数传递参数

3.运算符和&,以及运算符->*

&是取地址运算符(后面再讲引用的时候这个就变成引用运算符了)。 如

int a=5;  
cout<<&a<<endl;//使用&获取变量a的内存地址

*是指针运算符或间接引用运算符(注意:如果*用于声明指针,那么它就是指针说明符,如下)

int a=1;  
int *p=&a;//这里的*表明是指针说明符  
cout<<*p<<endl;//这里的*表示指针运算符,使用*获取指针变量p中保存的地址处的值,也就是1  

->是成员指针运算符或指向成员运算符

4.复杂变量的解释(要判断是一个变量的类型就看与他最先结合的运算符是什么),举例如下:
int p 变量p是一个普通的整形变量

int *p 由于变量p先与运算符*结合,所以p本质是一个指针,再与int结合,所以p就是一个指向整形数据的指针

int p[3] 由于变量p只与运算符[]结合,所以p本质是一个数组,再与int结合,所以p就是一个由整形数据组成的数组

int *p[3] 变量p先与[]结合,因为[]的优先级高于,所以p本质上是一个数组,剩下的就是要知道p是一个什么数组,然后p再与结合,说明是p是一个指针数组,然后再与int结合,说明p是一个指向整形数据的指针所组成的数组

int (*p)[3] 由于()改变了优先级,所以变量p先与*结合,所以p本质上是一个指针,那它是什么类型的指针呢,然后p再与[]结合,说明p是一个指向数组的指针,然后再与int结合,说明p是一个指向整形数据组成的数组的指针

int **p 变量p先与结合,说明p本质是一个指针,那它是什么指针呢,然后再与结合,说明p是一个指向指针的指针,然后再与int结合,说明p是一个指向整形数据的指针的指针

int p(int a)p首先与()结合,说明p是一个函数,然后进入()分析,发现函数有一个int型的参数a,然后再与int结合,说明p是具有整型参数且返回类型为整型的函数。

int (*p)(int a) 由于(p)改变了优先级,所以p先与结合,说明p本质是一个指针,然后再与(int a)结合,说明p是一个函数指针,然后再看(int a)发现函数具有一个int型的参数a,然后再与int结合,说明p是一个指向具有整型参数且返回类型为整型的函数的指针

5.指针的四方面重要内容

指针的类型,指针所指向的类型,指针的值(指针所指向的内存区),指针本身所占据的内存区

5.1 判断这四个方面的规则

指针的类型:把指针声明语句的指针名字去掉,剩下的部分就是指针的类型

指针所指向的类型:把指针声明语句里的指针名字和名字左边的指针声明符*去掉,就是指针所指向的类型

指针的值:在32位程序里,所有类型的指针的值都是一个32位整数,指针的值是指向的内存区域的首地址

指针本身所占据的内存区:指针本身占据的内存长度可以使用sizeof(指针的类型)测一下就知道,在32位平台里,指针本身占据了4个字节的长度

举例说明指针的类型和指针所指向的类型

举例 指针(ptr)(本身)的类型 指针所指向的类型
int *ptr int * int
char *ptr char * char
int **ptr int ** int *
int (*ptr)[3] int (*)[3] int ()[3]
int (ptr)[4] int ()[4] int *()[4]

6.指针与常量

声明定义式 注释
常量指针 int *const p; 指针本身不可改变,指向的变量可变
指向常量的指针 const int *p; 指针本身可变,其指向的变量不可变
指向常量的常指针 const int *const p; 指针本身不可变,其指向的变量也不可变

** 7.指针的注意事项:迷途指针**

定义一个指针之后,如果没有给他赋初值,那么该指针就是一个迷途指针,它可以指向任何地址,并且如果对该指针进行操作就会对位置区域的数据进行修改或删除,照成意想不到的后果,所以解决办法是将定义的指针进行初始化,如下

[cpp] 
int *p=0;

这样,这个指针就称为空指针

不仅在初始化的时候,还有一种情况迷途指针也会造成危害,就是删除指针delete p;之后,虽然指向的内存空间释放了,但是指针本身还存在,如果再次使用该指针也会造成很严重的后果,所以再删除一个指针之后,将该指针赋值为空。虽然空指针是非法的,容易是程序奔溃,但是我们宁愿程序崩溃,也不愿意调试起来很困难。如下:

int *p=new int;  
delete p;  
p=0;  
[cpp] view plain copy print?
*p=23;  

删除指针p后,赋值为0,然后在使用该空指针,程序运行的时候,运行到*p=23就会报错,这样我们就知道我们使用了一个迷途指针,从而及时修改程序。要是我们将p=0这句话去掉,那么程序就不会报错,但是何时崩溃就不知道了,这样加重了我们查问题的难度。

二.引用

1.引用的概念:引用就是别名,如

[cpp]
int &rnum=num;//这里的&是引用运算符 

rnum是整形变量num的别名,这样,对rnum的操作实际就是对num的操作

这里要注意,别名rnum前面的符号&不是取地址运算符,而是引用运算符。

2.引用的作用(为什么要用“引用”)

其实引用只是为变量另外起了一个名字,就像#define num rnum==(int &runm=num),将num定义成rnum,两者在内存中是同一个空间。引用它不像int rnum=num;rnum其实是在内存中新分配了一个空间,所以rnum和num占据的是两个不同的内存空间。那么引用在程序中到底有什么用呢?

我们知道我们在传函数的参数的时候,分两种:按值传递按地址传递

按值传递
void swap(int a,int b)

按值传递,编译器会自动在栈中创建a和b的副本,如果形参不是int类型,而是类类型,那么副本就会很大,效率很低,这时候就要考虑按地址传递

按地址传递

[cpp] 
void swap(int *a,int *b)  
{  
   int c;  
    c=*a;  
    *a=*b;  
    *b=c;  
}  

上面的功能是达到了,把指针作为函数的接受参数虽然能正常使用,但是它却不易阅读,而且很难使用。这时候引用作为形参就派上用场了:

如果引用作为参数,在函数内部可以修改a的值和b的值,这样破坏了按值传递的保护机制,不过我们可以使用const来声明一个不可修改值的引用,假设我们不想在函数内修改a的值,那么上面的代码修改如下:

[cpp] 
<span style="font-size:14px;">void swap(const int &a,int &b)  
{  
   int c;  
    c=a;  
    a=b;//编译报错:不能给常量a赋值  
    b=c;  
}

通过上面的代码,a就不能被赋值了,这样a就被称为常引用
总结:引用在使用中单纯的给某个变量取个别名是没有意义的,引用的主要目的是可以作为按地址的参数传递还可以作为函数的返回值(注意:局部变量是不能返回引用的,因为局部变量在函数返回后会被销毁)

3.引用的两个特点:

第一:定义引用的同时要对该引用进行初始化,否则编译不能通过。如下

[cpp] 
//正确的定义引用  
int a=0;  
int &ra=a;  
//错误的定义引用ra,必须进行初始化  
int a=0;  
int &ra;  
ra=a;  

第二:引用可以改变其指向地址的数据,但是不能改变其自身的地址(也就是说别名的地址是不会被改变的,但是别名的值会变),如

[cpp] 
int a;  
int &ra=a;  
a=999;  
cout<<"a="<<a<<"  "<<"&a="<<&a<<endl;//a=999 &a=0012ff60  
cout<<"ra="<<ra<<"  " <<"&ra="<<&ra<<endl;//ra=999 &ra=0012ff60  
  
int b=1000;  
ra=b;  
cout<<"a="<<a <<"  "<<"&a="<<&a<<endl;//a=1000 &a=0012ff60  
cout<<"ra="<<ra<<"  " <<"&ra="<<&ra<<endl;//ra=1000 &ra=0012ff60  
cout<<"b="<<b <<"  "<<"&b="<<&b<<endl;//b=1000 &b=0012ff48  
  
ra=1;  
cout<<"a="<<a <<"  "<<"&a="<<&a<<endl;//a=1 &a=0012ff60  
cout<<"ra="<<ra<<"  " <<"&ra="<<&ra<<endl;//ra=1 &ra=0012ff60  
cout<<"b="<<b<<"  " <<"&b="<<&b<<endl;//b=1000 &b=0012ff48  

上面的例子中ra=b之后,查看ra的地址可以看出来,ra的地址并没有变化,也就是说ra是a的别名,那么就不可能变成其他变量(b)的别名,对ra的操作还是在操作a,而不是b,所以最后在ra=1之后改变的还是a的值。

4.引用的注意事项

4.1 引用声明的时候必须进行初始化 int num=5;int &rnum=num;

4.2 不能建立数组的引用(int &a[5]),不能建立引用的引用(int &&a),不能建立引用的指针(int &*a),

4.3 可以建立指针的引用:

[cpp] 
int *p;  
int *&q=p;

上面的q与它最先结合的运算符是&,所以他的本质是一个引用,然后再与*结合,所以q是一个指针的引用,也就是指针p的别名。

4.4 引用在作为函数的返回值的时候,千万注意,局部变量是不能作为返回值的,因为局部变量在函数返回的时候已经被释放了,如下:

[cpp]
class A  
{  
  
}  
  
A &func()  
{  
     A a;  
     return a;  
}  

上面的func函数返回的是局部变量类A的对象a,如果外部使用了它会报错,因为局部变量a在函数返回的时候已经被释放了。

三.指针和引用

1.首先对指针和引用的运算符&和*进行说明:

运算符&*在声明定义的时候(包括形参的声明)称为引用运算符(声明变量是引用)和指针说明符(声明变量是指针);它们在使用的时候称为取地址运算符(获取变量的内存地址)和指针运算符(获取指针指向的地址里的内存数据),例如:

运算符&

[cpp] 
int a=5;  
int &a1=a;//引用运算符  
cout<<&a1<<endl;//取地址运算符  
int func(int &a,int &b);//引用运算符  

运算符*

[cpp] 
int b=6;  
int *b1=&b;//指针说明符;取地址运算符  
cout<<*b1<<endl;//指针运算符  
int func(int *a,int *b);//指针说明符  

2.常指针和常引用

它们的声明方式相同,都是使用const来定义,但是由于引用本身是不可更改的,所以不用这样声明:int const &a;

3.指针和引用的区别

指针可以为空,引用不可以。

指针可以被赋值,引用只能被初始化,不能被赋值。

在堆中创建一块内存区域,必须使用指针来指向它,不能使用引用来指向它,如int &r=new int;这句话是错误的。这时候你可以这样int *&r=new int;r表示一个指针的引用,也就是指向new int所在的堆区的指针的别名。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,387评论 3 44
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,446评论 1 51
  • 重新系统学习下C++;但是还是少了好多知识点;socket;unix;stl;boost等; C++ 教程 | 菜...
    kakukeme阅读 19,422评论 0 50
  • --help会在终端列出所有可用的命令,可以使用任何命令的-h或-help选项来查看该命令的具体用法 mac或li...
    吧啦啦小汤圆阅读 334评论 0 0
  • 春节聚在一起,七大姑八大姨们除了聊孩子还是聊孩子。于是,话题绕来绕去总是走不出这个弯: “你怎么还没个对象?!” ...
    小瑜姑娘阅读 357评论 1 3