指针和引用的总结

指针和引用的总结,第1张

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录
  • 前言

  • 一、指针

    • 1.首先要知道什么是变量?
    • 2.指针是什么?
    • 3.关于野指针和空指针
    • 4.二级指针

  • 二、引用

    • 1.什么是引用
    • 2.引用的目的
    • 3.关于引用作为函数参数
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

个人觉得C++中的指针和引用比较难搞定,所以我把我自己学到的总结起来,疑惑的时候可以再看看,有更深的理解也可以再写进去


提示:以下是本篇文章正文内容,下面案例可供参考


一、指针 1.首先要知道什么是变量?

变量的实质就是内存。


那什么又是内存呢,内存就是是一个存放数据的空间。



比如我们在定义 一个整型变量a的时候 :int a;其实质就是在内存中申请了一个名为 i 的整型变量宽度空间。


而这段空间有它自己的地址
可以用&(取址符)来查看这段空间的地址:

int a;
	cout << "整型变量a的地址:" << endl;
	cout << &a << endl;
	cout << "--------------" << endl;

我们可以打印看一下:

2.指针是什么?

1、我在学习指针的时候看到的都是关于指针的例子,讲一个印象比较深刻的;
加入我们要入住一个酒店,前台给我们说,我们的房间号是1111,然后给了我们一个房卡,我们拿着房卡可以打开1111的门。


房卡就可以理解为指针,
指向1111这个房间的地址;
指针的表示方式
int *p;
试一试,先定义一个整型变量a,然后让指针p指向变量a的地址;

int a = 10;
	//定义一个指针变量p指向a
int* p = &a;

cout << *p << endl;

我们可以通过打印*p来看到变量a里的数据

然后我们看一下就是刚学指针是一直搞不清的一些关于*p,&p,和p;
我们先打印一下

int a = 10;
	//定义一个指针变量p指向a
int* p = &a;

cout << "*p的值是:" << endl;
cout << *p << endl;
cout << "---------------------" << endl;

cout << "p的值是:" << endl;
cout << p << endl;
cout << "---------------------" << endl;

cout << "&p的值是:" << endl;
cout << &p << endl;
cout << "---------------------" << endl;

cout << "a的值是:" << endl;
cout << a << endl;
cout << "---------------------" << endl;

cout << "&a的值是:" << endl;
cout << &a << endl;

![在这里插入图片描述](http://www.kaotop.com/file/tupian/20220703/d120df737e5b4cda9fd391b3ea0d5b24.png#pic_center
我们可以看到,&a也就是变量a的内存地址和p的值是一样的,也就是说定义指针p里面的内容是变量a的地址,而*p也就是它所指地址的内容,也就是a的值。



而指针变量,既然是变量,自然有它自己的地址,也就是上面那一串:00ECF9D8 指针p的地址
整体的意思就是说:指针p(地址为:00ECF9D8)里面储存着:00ECF9CC
这么一串地址,而这个地址是变量a(地址为:00ECF9CC)它的地址。



p: 指向的地址
*p:指向的地址里面的内容
&p: 指针p的地址

3.关于野指针和空指针

1、空指针:

在定义指针的时候,未将其初始化,那么这个指针指向的就是一片未知的内存地址,系统会报错。



所以要在定义指针的时候将其初始化 如:

int a = 10;
//定义一个指针变量,让其指向一个合法的内存地址
int* p = &a;
//给指针开辟一段空间
int* p = new int()
//手动开辟的空间要记得手动释放
delete p;
//置为空   标志指针变量没有指向任何变量(空闲可用)
int* p =NULL;

空指针的意义就是:通常把NULL赋值给此指针,这样就标志此指针为空指针,没有指向任何空间。



注意:从定义上看,NULL指针并没有指向任何东西,所以对一个空指针解引用是一个非法 *** 作,要在解引用前,必须确保它不是一个空指针。


2、野指针
什么是野指针,就是:指针指向的内存地址是未知的。


当指针被创建时,不会自动称为NULL指针,它指向的地址是随机的。



下面说一下会出现野指针的几种情况
(1)定义指针变量的时候未初始化

int a = 20;
int* p;
*p = 20;

系统会报错

(2)指针访问越界

int arr[10] = { 0 };
int* p = arr;
	
	
for (int i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
//数组大小只有10,而遍历到11则会出现指针越界现象,系统会报错
for (int i = 0; i < 11; i++)
	{
		cout <<*(p + i) << endl;
	}

指针 *** 作超越了变量的作用范围

A *p; // A为一个自定义对象
 {
     A a;
     p = &a; // 注意 a 的生命期 ,只在这个程序块中(花括号里面的两行),而不是整个test函数
  }
p->Func();  // p是“野指针”

(3)释放掉的指针未置为空

//创建一个指针并将其初始化
int* p = NULL;

	//为指针p开辟一个堆空间大小为10个int大小,
p = new int(10);

	//判断一下是否开辟成功,如果开辟失败则返回
if (!p)
	{
		return;
	}
	//使用完后释放指针
delete[]p;

	//释放完后要重新置为空,如果未置空,则会变成野指针
p = NULL;	

我们讲了野指针的出现情况,接着说一说如何避免出现野指针
(1)创建时要记得初始化
(2)防止指针越界访问
(3)避免返回局部变量的地址
(4)释放开辟的指针后要将其置为NULL

4.二级指针

二级指针就是一个指向一级指针(int *p)的指针,通常我们可以通过二级指针实现间接访问数据,和改变一级指针的指向。


int a = 10;

int* p = &a;   //定义一个一级指针指向变量a的内存地址
int** pp = &p; //定义一个二级指针指向指针p的内存地址

	//分别打印一下
cout << "a的值为:" << a << endl;
cout << "a的地址为:" << &a << endl;
cout << "p的值为:" << p << endl;
cout << "                                  " << endl;

cout << "*p的值为:" << *p << endl;
cout << "一级指针p的地址为:" << &p << endl;
cout << "pp的值为:         " << pp << endl;

cout << "                                  " << endl;
cout << "**pp的值为:" << **pp << endl;
cout << "二级指针pp的地址为:" << &pp << endl;

打印一下结果可以看到

二级指针里面放的是一级指针的地址,二级指针可以通过访问一级指针来间接的访问到一级指针指向的内存地址,也就是变量a的数据

刚刚说到通过指针来修改它所指向的值,我们在二级指针里一起看一下

int a = 10;

int* p = &a;   //定义一个一级指针指向变量a的内存地址
int** pp = &p; //定义一个二级指针指向指针p的内存地址

*p = 20;
cout << a << endl;//最后打印看到a的值为20

**PP=30;
cout << a << endl;//最后打印看到a的值为30

可以通过一级指针,修改 0 级指针(变量)的内容。



可以通过二级指针,修改一级指针的指向。



可以通过三级指针,修改二级指针的指向。



二、引用 1.什么是引用

引用就是给这个变量起了个外号,也就是别名,对引用的 *** 作与对变量的直接 *** 作是一样的。



引用的声明方法是:目标变量类型标识符&引用名=目标变量名

int a = 10;
int& b = a;

cout <<"a的值为:"<< a << endl;
cout <<"b的值为:" << b << endl;
cout <<"a的地址为:"<< &b << endl;
cout <<"b的地址为:" << &a << endl;


我们可以看到b的地址和值与a的完全一样,也就是说,它们就是同一个东西。



我们讲一下关于引用的几个点
*&是起别名的一个标识符,不是取地址。


*在声明引用的同时,必须对其进行初始化,引用一块合法的内存空间
:比如说 int a = 10;//那么a就是一块合法的内存空间
可以进行引用 *** 作 int& p = a
如果直接让 int& p = 10 //会错误,因为10不是一块合法的内存空间。


*不能返回局部变量的引用。


为什么呢?
因为吧,局部变量是有生命周期,在函数内部或者复合语句内部定义的变量称为局部变量,它只在起作用域内(函数内部 \ 符合语句内部)有效。


PS:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时,这些存储单元会自动释放。



所以释放掉了,当然就什么都没有了,就会变成引用一块不合法的内存空间。


我们试一下:

int& test()
{
	int a = 10;
	return a;
}
void test10()
{
	//cout << test() << endl;
	int& p = test();

	cout << p << endl;
	cout << p << endl;
	
}


第一次可以打印出来,但是多打印几次就会发现问题,为什么呢?我也是刚刚了解:局部变量存储的地方是在栈上,栈里面数据不是在调用完这个函数就销毁了,而是在调用下一个函数之前销毁,所以第一次可以打印是因为还没有销毁数据。



*不能建立引用的数组。


因为数组是由若干个元素组成的集合,所以无法建立一个由引用组成的集合,但是可以数组的引用。


2.引用的目的

*引用的主要目的是在函数参数传递中,解决大块数据或对象的传递效率和空间问题。



*用引用传递的参数,能保证在传递的过程不产生额外的副本,提高传递的效率,加上const,还可以保证引用传递的安全性
*

3.关于引用作为函数参数
//1.【值传递】如果形参为非引用的传值方式,则生成局部临时变量接收实参的值
void Swap(int left, int right) 
{//值传递的方式无法实现交换,因为传参时对于参数left和right拷贝一临时副本,交换的是副本值,因为其是临时变量函数退出,变量销毁,并不会影响外部left和right的值。


int temp = left; left = right; right = temp; } //2.【引用传递】如果形参为引用类型,则形参是实参的别名。


void Swap(int& left, int& right)//使用引用的话,不做临时拷贝,&的使用说明此处只是原参数的另一个名字而已,所以修改时直接在原参数的基础上修改变量值。


{ int temp = left; right = left; left = temp; } //3.【指针传递】 void Swap(int* pLeft, int* pRight)//传入的是地址,因为地址是唯一的,所以指针通过地址的访问进而可修改其内容。


{ int temp = *pLeft; *pLeft = *pRight; *pRight = temp; }

总结

引用和指针的区别:
1、从本质上来看,指针有自己的一块空间,而引用只是一个别名;
2、从大小上看,一个指针的大小(32位下)为4个字节,而引用则是被引用对象的大小。



3、指针变量在创建的时候需要被初始化,指向某一块内存地址,或者初始化为NULL,而引用必须被初始化,且必须是一个已有对象的引用。



4、指针在使用的过程中,可以指向其他对象,但是引用只能是一个对象的引用。



5、引用只有一级,但是指针可以有很多级。



6、使用指针进行传参的时候,还是值传递,指针本身的值不可以修改,需要进行解引用来 *** 作指向的对象;但是引用传参的时候,传进来的就是变量本身, 直接对引用的修改都会改变引用所指向的对象。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/langs/565164.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-06
下一篇 2022-04-06

发表评论

登录后才能评论

评论列表(0条)

保存