前言:
本文涉及的全部是基础的C++知识点,主要针对C++初学者和新手入门。
学习了一段时间的C++之后,特别是刚刚开始接触时,对于指针这个东西确实感觉有些抽象,所以写了这篇文章,希望在总结这部分的知识点的时候,顺便能够给和我一样的C++初学者提供一些小小的帮助。(我自己也是一个刚入门的小菜🐓,如果文章中有不对的地方,希望大佬能够不吝赐教,跪谢😘)
一,什么是指针
我们都知道,如果在程序中定义了变量,那么在编译程序的时候,编译器就会给变量分配内存单元。内存区的每一个字节都有一个独一无二的编号,这就是我们所说的“地址”。在这里,我们首先要切记区分清楚内存单元的地址和内存单元的内容这两个前期比较容易混淆的概念。
在我们刚开始接触C++的时候,一般都是通过 直接使用变量名 来对内存单元进行存取操作的,这是一种较为直接地存取变量值的方式。
但是如果我们不这么做,而是首先将变量(int x)的地址存入到另一个变量(int *x_pointer = &x)中,再通过这个变量x_pointer间接地去访问变量x,那么一样可以到达和上面(直接使用变量名)一样的效果,也能够对变量进行存区操作。由于通过上面这个方式,我们知道,通过地址能够找到所需的变量单元,所以我们可以说,地址指向该变量单元。因此,我们将地址形象化地称作“指针”(Pointer)。
即,一个变量的地址称作该变量的指针。
OK,有意思的来了。如果说,我们大胆一点,用一个变量专门地来存放另一个变量的地址(也就是刚刚我们说到的“指针”),那么这个玩意就是我们的另一个新概念——指针变量。
这里要仔细甄别两者的概念,区分指针和指针变量。
指针:说白了就是一个变量的地址
(这句话不完全正确,只是为了反映地址与指针之间密不可分的关系)。
指针变量:一种特殊的变量,作用是用来存储另外一个变量的地址。指针变量的值(变量的内容)是地址(指针),而这个地址又指向内存中的某一位置。(绕晕了有没有😵)
(指针就是地址。所以说,指针变量存储的是地址,也就是指针,它本身又是一个变量,所以,我们叫它“指针变量”合情合理又合法吧 🙈)
还有一点就是指针的指向,我前面没有提及过,因为很容易理解,就是字面意思。指针的指向就是指针指的方向呗👀
如果可以理解和分辨以上提到的概念,可以直接空降到下一个部分。
如果理解起来还是有点抽象,那么我们可以做一个小小的比喻。
我们可以把整体的内存看作是一家酒店,酒店的房间就是我们的内存空间,而门牌号就类似于我们所说的 地址( 地址是一串十六进制的编码)。那么也就是说,一个门牌号对应一个与之匹配的房间(也就是一个地址对应一片内存空间),而如果我们要进入房间,肯定是要拥有对应的门禁卡才行。
那么我们就可以进行一个形象的比喻,把酒店看成内存空间,房间看成内存单元,门牌号看成地址,门禁卡看成指针变量。
所以,我们要想使用酒店的房间(也就是我们要使用内存),那么就需要一张门禁卡(一个指针变量),一张门禁卡对应(指向)一个房间(指针变量内存放另一个变量的地址,指向某一地址),我们就可以通过门禁卡(指针变量)进入对应的房间(使用指针变量访问对应的内存空间,进行相关的操作),房间的门牌号就是内存单元的地址,房间里面放的东西就是内存单元的内容。
二,为什么要使用指针
为什么要使用指针???🐵🐵🐵
说实话,就我目前的学习阶段还不能够完全回答这个问题,但是在学习过程中确实也是亲身地体会到了使用指针的便捷之处。以下是我对于为什么要使用指针的看法,回答不全面,如果有其他的看法,可以在评论区讨论。
为什么要使用指针? //指针的好处
指针的使用使得不同区域的代码可以轻易的共享内存数据
虽然我们可以在需要使用的时候对数据进行复制,但是多次的复制数据也就意味着时间和空间的开销,因此这样会降低我们程序的运行效率,而指针的使用可以极大程度上的解决这个问题。
举个栗子,某些函数在进行参数传递的时候传输的是占用较大内存的数据,比如结构体,而使用指针的话,就可以节约大把的空间开销,具体原因在下文会讲到。
一些复杂的结构需要使用指针来构建(比如链表,二叉树等)
进行地址传递的时候,使用指针往往会比较方便
//以下是一个很简单的例子:
void swap1(int a,int b)//形参使用值传递
{
int temp = a;
a = b;
b = temp;
}
void swap2(int *a,int *b)//形参使用地址传递
{
int temp = *a;
*a = *b;
*b = temp;
}
调用这两个函数之后的结果显而易见
我们知道swap1只是形参进行了交换操作,实参并没有发生实际上的改变。
而swap2进行的是地址的传递,输出结果后我们知道,使用指针作为参数时,可以达到我们进行数据交换的目的,而这是swap1无法做到的!
程序猿对申请的堆空间进行操作(动态空间的分配)
因为我们申请的堆空间往往是只能够通过指针的方式进行访问和使用的
函数返回多个返回值
对数组进行操作时,使用指针比使用数组下标的效率更高
其实刚开始的时候对于指针的使用不够熟练,感觉不如直接使用变量名和下标来的方便。但是实际上,一旦深入地继续学习下去,我相信各位一定能够深刻地明白使用指针的便捷和强大。
三,How to use?
OK,指针的概念讲的也七七八八差不多了,接下来我们聊聊这个东西究竟怎么去使用。
指针的大小
首先,我们需要知道的是,C++中所有的变量都必须先定义后才能够使用,系统会根据数据类型分配存储空间,VC++中每个指针变量分配4个字节
这就是之前在上面提到的使用指针可以节约空间的原因,因为无论指针指向的内容多大,指针变量永远都是4个字节,可以极大的节约空间的开销。
指针的定义
定义一个指针变量的一般形式为:基类型 *指针变量名;
eg:
int a = 10;
int *i_p = &a;//定义一个int*类型的指针指向变量a
Tips:
在定义指针变量的时候必须指定其基类型
一个指针只能指向同一个类型的变量
不能使用一个整数给一个变量赋初值,只能够使用&取地址赋给指针变量或者数组名
指针变量名的命名也要符合标识符的命名规则
对于一个指针变量的完整描述(以上述例子为例):i_p是指向int类型数据的指针变量
引用指针变量
& 取地址运算符
* 指针运算符(或称间接访问运算符)
例如:
&a为变量a的地址
*p为指针变量p所指向的存储单元
对于&和*的使用说明:
若p1 = &a;那么&*p与&a等价,*&a与a等价。
实际上,根据基类型的不同,指针可以分为int*指针,float*指针,甚至函数指针,结构体指针,对象指针等等,这里暂时不进行详细地展开,如果需要对这些进阶的指针用法展开讨论,我将会在之后的文章中来详细说明。
还有一点,指针是可以作为函数的参数的,这点在上面的指针的好处部分有提及。
接下来看一个十分经典的案例:
输入a和b两个整数,按先大后小的顺序输出a和b(用指针变量处理)
#include <iostream>
using namespace std;
int main()
{
void swap(int*p1,int *p2);
int* pointer_1,* pointer_2,a,b;
cin>>a>>b;
pointer_1=&a;
pointer_2=&b;
if(a<b) swap( pointer_1, pointer_2);
cout<<"max="<<a<<"min="<<b<<endl;
return 0;
}
void swap(int*p1,int*p2)
{
int *temp;
temp=p1;
p1=p2;
p2=temp;
}
你不会真的以为这段代码可以实现上述功能吧?😤
我们仔细看看,简单地画个流程图
![](https://i-blog.csdnimg.cn/blog_migrate/cfce64e50a54419ebb2cf19cc8fddb25.jpeg)
哇哦,发现了不得了的东西👀
实际上,这样子并不能够达到我们的目的。因为实参和形参之间的数据传递是单向的“值传递”方式。指针变量作为函数参数时也得遵循这个规则。调用函数时不会改变实参指针变量的值,但是可以改变实参指针变量所指向变量的值。
注意:不能试图通过改变形参指针变量的值而使实参指针变量的值改变。
四,this指针
this指针是一个极为特殊的指针,主要在类的学习中才会接触并使用这个指针,而且它是由系统自动生成的,且自动隐藏,一样的,在此我们不进行详细的展开,仅仅是为大家提及一下这个东西,让大家有一点印象,在之后的学习过程中遇到的时候知道存在这个特殊的指针,针对this指针的使用会在后续文章中进行较为详细地说明。
五,小结
All in all,全文重心主要在于对指针的基础知识的讲解与理解,内容十分基础,主要目的为后续C++的学习打下坚实的基础,涉及的知识点内容不多,但是对于初学者还是较为繁琐且易混淆,建议在观看完文章后自己亲自上机去简单地使用一下指针,多多加以训练。
下面是我自己在学习指针的时候去理解指针和使用指针的部分代码,如果喜欢我的风格,可以持续关注我(小菜鸟一枚),见证我们一起变秃,哦,不,变强的过程!😆
#include<iostream>
using namespace std;
int main()
{
//指针的定义语法: 数据类型 * 指针变量名
/*可以这么理解,指针是一个存储地址的变量。*/
int a = 231;
int* p;//定义一个指针
p = &a;//用指针记录变量a的地址,&为取址符号
cout << "a的地址为:" << &a << endl;
cout << "指针p为:" << p << endl;
//指针的使用:
//可以通过解引用的方式来找到指针指向的内存
//指针前加上 * 代表解引用,找到指针指向的内存中的数据
cout << "变量a:" << a << endl;
cout << "指针p:" << *p << endl;
cout << "p = " << p << "\n(p 保存的是变量 a 的地址,所以输出的是一个十六进制的数值)" << endl;
cout << "进行新的赋值操作后" << endl;
*p = 520;//用解引用的方式对 a 进行赋值操作
cout << "a = " << a << endl;
cout << "*p = " << *p << endl;
//总结:
// * 取内容 & 取地址
cout << "指针p的内存大小为:" << sizeof(p) << endl;
cout << "char型指针的内存大小为:" << sizeof(char*) << endl;
cout << "double型指针的内存大小为:" << sizeof(double*) << endl;
cout << "float型指针的内存大小为:" << sizeof(float*) << endl;
//总结 :(不管是什么数据类型的指针)
//在32位操作系统下,指针占 4 个字节
//在64位操作系统下,指针占 8 个字节
return 0;
}
路漫漫其修远兮
坚持且热爱是我最大的动力!