前言:本文将讲解指针的定义、指针变量和普通变量的本质区别、一级指针和二级指针的关系以及如何通过二级指针修改一级指针所指向的内存。文末还附加了两个实例,帮助读者加深对二级指针的理解。本文试图通过图表的方式,通俗地讲解指针和二级指针,让读者对此有深入的理解。阅读本文大概需要15分钟的时间。
1、指针的定义:
int a = 1; //普通变量的定义
int *pA = &a; //指针的定义
或者
int *pA = NULL;
pA = &a;
符号&表示“取址符”,也就是获取上面的变量a所在内存空间的地址。
从上面指针的第二种定义中就可以看出,变量pA的值等于变量a的内存地址。星号*的作用是表明变量pA是一个指针变量。那么,普通变量和指针变量的区别是什么呢?
2、普通变量和指针变量
普通变量:(变量名字name,变量值value,变量的内存地址addr)
指针变量:(变量名字name,变量值value,变量的内存地址addr)
从表面上看,普通变量和指针变量没有多大区别。实质上的区别是:指针变量的变量值value
存储的是一个用16进制表示的32位内存地址,比如00A6F790。而普通变量的变量值value
所存储的内容没有限制。还有,指针变量能够根据变量值value
中的内存地址获取到该地址所对应的值(假设指针变量名为p,通过*p来获取)。具体看下面的关系图:
其中,上图中变量的定义为:
int commonVar = 12;
///
string str = "hello";
string * poiterVar = &str;
poiterVar = “00ER343O”
*poiterVar = “hello”;
所以,指针变量和普通变量没有太大区别。
###3、 一级指针和二级指针的关系
那么,对于指针的指针呢?
上图中两个指针的定义为:
string str = "hello";
string *poiterVar1 = &str;
string **poiterVar2 = &poiterVar1;
暂时不要考虑*星号,避免被星号搞混了。星号的作用有两个,一是在指针定义的时候表明该变量是指针变量以及是几级指针(有几个星号就表示几级),二是能够通过指针变量所指向的内存地址(或者说上图中Value的值)来获取对应内存的内容。比如上图中的poiterVar1
通过Value = 00ER343O
来获取hello
,即*poiterVar1
。
从上图中还可以看出,一级指针poiterVar1和二级指针poiterVar2没有什么区别。如果非要说出一点区别的话,就是在指针定义的时候,后者多加了一个*星号。
指针变量修改所指向的内容的时候,因为指针指向的是其内存地址,所以,就相当于把该内存中的内容修改了。这一点是指针强大的原因所在,也是它存在的原因。
4、实例讲解1
上图中两个指针的定义为:
string *poiterVar1 = NULL;
string **poiterVar2 = &poiterVar1;
指针变量poiterVar1初始化的时候指向了NULL。可以通过poiterVar2修改poiterVar1,让它指向一个非NULL的内容吗? 是可以的。怎么做到呢?
问题可以转换为:让pointerVar1中的Value等于一个有效的内存地址。具体怎么做呢?因为poiterVar2拥有poiterVar1的内存地址,所以,可以通过poiterVar2来修改poiterVar2变量中的值(也就是它的Value)。具体如下:
string *poiterVar1 = NULL;
string **poiterVar2 = &poiterVar1;
string str = "hello";
/*
if (*poiterVar2 == poiterVar1)
cout << "*poiterVar2 == poiterVar1" << endl;
else
cout << "*poiterVar2 != poiterVar1" << endl;
*/
*poiterVar2 = &str;
cout << *poiterVar1 << endl;
//执行结果
//*poiterVar2 == poiterVar1
//hello
上面代码中,*poiterVar2
代表poiterVar1的Value,把str的内存地址赋值给*poiterVar2
就可以了。
5、实例讲解2
本实例和第一个实例基本相同,只是把string类型变成了自定义的Teacher类型。开始的时候Teacher类型的指针为NULL,通过一个二级指针让一级指针指向一个有效的内存空间。也是指针的指针的问题,一级指针是teacherObj,二级指针是pTeacher(函数的参数)。
在代码中它们的关系可以表示为:
Teacher *teacherObj = NULL;
Teacher **pTeacher = &teacherObj;
所以,这个实例和第一个实例是一样的。
#include <iostream>
#include <string>
using namespace std;
struct Teacher {
int age;
char* name;
};
int getTeacher(Teacher **pTeacher){
if (pTeacher == nullptr)return -1;
Teacher * tmpTeacher = (Teacher*)malloc(sizeof(Teacher));
if (tmpTeacher == nullptr) return -1;
tmpTeacher->age = 32;
tmpTeacher->name = "Liangyihuai";
*pTeacher = tmpTeacher; //*pTeacher就代表一级指针的value值。
return 1;
}
int main() {
Teacher *teacherObj = NULL;
getTeacher(&teacherObj);
cout << teacherObj->age << " " << teacherObj->name << endl;
system("pause");
return 0;
}
拓展:
上面的getTeacher方法也可以写成:
int getTeacher2(Teacher* &pTeacher) {
Teacher * tmpTeacher = (Teacher*)malloc(sizeof(Teacher));
if (tmpTeacher == nullptr)return -1;
tmpTeacher->age = 32;
tmpTeacher->name = "Liangyihuai";
pTeacher = tmpTeacher;
return 1;
}
//在main函数中:
//Teacher *teacherObj = NULL;
//getTeacher2(teacherObj);
其中引用pTeacher表示teacherObj,也就是pTeacher是teacherObj的一个别名,而teacherObj是一个指针变量,所以,让pTeacher等于一个有效的内存空间就可以了。
6、总结:
本文讲解了指针变量和普通变量的区别。分析了二级指针和一级指针的区别和本质,以及如何使用二级指针修改一级指针所指向的内存空间。如果有误,欢迎指教。