序言
我们平时所说的指针其实是指针变量。而指针变量,顾名思义,是含有指针的变量。而这个指针指的是内存地址。所以指针变量也可以说是含有内存地址的变量。
指针
系统的内存就像是带有编号的小房间,如果想使用内存就需要得到房间号。假如定义一个整型变量i,它需要4个字节,这个时候编译器为变量i会分配连续编号的小房间,比如4001到4004.每个房间代表一个字节。
一个变量在内存中的存储
在程序代码中通过变量名来对内存单元进行存取操作,代码经过编译后会将变量名转换为该变量在内存的存放地址,对变量值的存取是通过地址进行的。比如,变量i在参与计算的时候,会找到变量名对应的内存地址,首先会找到变量i的地址4001,然后从4001开始读取4个字节数据放到CPU的寄存器中。
由于通过地址能访问指定的内存存储单元,可以说地址“指向”该内存单元,例如房间号4001指向系统内存中的一个字节。地址可以形象的称为指针,即一个变量的地址可以形象的称为该变量的指针。
指针变量
一个变量的地址可以形象的称为该变量的指针,所以存放指针(内存地址)的变量,就是指针变量,而这个变量的类型,称为指针类型。
我们平时所说的指针,是指"指针变量",而不是内存地址,毕竟我们写代码,是通过变量操作地址,而不是直接操作地址。
即我们平时说的指针是一种数据类型,通常说的指针就是指针变量,它是一个专门用来存放地址的变量,而变量的指针主要指变量在内存中的地址。
下文所说的指针都指的是指针变量。
指针的声明和赋值以及关于指针使用的说明
- 声明
int *i;
float *a,*b;
分别声明了整型指针和浮点指针。
- 赋值
- 初始化时赋值
int i = 100;
int *p_ipoint = &i;
- 后期赋值
int *p_ipoint;
int i = 100;
p_ipoint = &i;
- 说明
int p_ipoint; ------ 指针变量名是p_ipoint,而不是p_ipoint。
p_ipoint = &i; ------ 指取变量i的地址赋值给变量p_ipoint。
取值运算符和取地址运算符
"*" 和 "&" 是两个运算符,前者是取值运算符,后者是取地址运算符。
- 获取变量的地址值
int a = 100;
int *p = &a;
printf("%d\n",p);
-536471336
- 输出指针对应的数值
int a = 100;
int *p = &a;
std::cout << " a=" << a << std::endl;
std::cout << " p=" << *p << std::endl;
a=100
p=100
指针运算
指针变量存储的是地址值,对指针做运算就等于对地址做运算。
- 输出指针运算后的地址值
int a = 100;
int *p = &a;
printf("address:%d\n",p);
p++;
printf("address:%d\n",p);
p--;
printf("address:%d\n",p);
address:-422471464
address:-422471460
address:-422471464
说明:定义指针变量必须指定一个数据类型。
指向空的指针与空类型指针
指针可以指向任何数据类型的数据,包括空类型(void): 定义如下:
void *p;
空类型指针可以接受任何类型的数据,当使用它时,可以将其强制转化为所对应的数据类型。
int *pI = NULL;
int i = 4;
pI = &i;
float f = 3.333f;
bool b = true;
void *pV = NULL;
cout<<"依次赋值给空指针"<<endl;
pV = pI;
cout<<"pV = pI ----- "<<*(int*)pV<<endl;
cout<<"pV = pI ----- 转为float类型指针"<<*(float*)pV<<endl;
pV = &f;
cout<<"pV = &f ----- "<<*(float*)pV<<endl;
cout<<"pV = &f ----- 转为int类型指针"<<*(int*)pV<<endl;
依次赋值给空指针
pV = pI ----- 4
pV = pI ----- 转为float类型指针5.60519e-45
pV = &f ----- 3.333
pV = &f ----- 转为int类型指针1079332831
可以看到空指针被赋值后,转化为对应类型的指针才能得到我们所期望的结果。若将它转换为其他类型的指针,得到的结果将不可预知,非空指针类型指针同样具有这样的特性。
指针常量与指向常量的指针
- 指针常量
同其他数据类型一样,指针类型也有常量,使用const关键字形式如下:
int i = 9;
int* const p = &i;
cout<<"指针变量p中的指针指向的内存地址是"<<p<<endl;
cout<<"指针变量p中的指针指向的内存地址是"<<*p<<endl;
*p = 3;
cout<<"指针变量p中的指针指向的内存地址是"<<p<<endl;
cout<<"指针变量p中的指针指向的内存地址是"<<*p<<endl;
指针变量p中的指针指向的内存地址是0x7ffee86d58d8
指针变量p中的指针指向的内存地址是9
指针变量p中的指针指向的内存地址是0x7ffee86d58d8
指针变量p中的指针指向的内存地址是3
将关键字const放在标识符前,表示这个数据本身是常量,数据类型是int*,即整型指针。与其他常量一样,指针常量必须初始化。我们无法改变常量指针的内存指向,但是可以改变它指向内存的内容。
- 指向常量的指针
若将关键字const放到指针类型的前方,形式如下:
int i = 9;
int const *p = &i;
这是指向常量的指针,虽然其所指向的数据可以通过赋值语句进行修改,但是通过该指针修改内存内容的操作是不被允许的。
- 当const以如下形式使用时:
int i = 9;
int const* const p = &i;
该指针是一个指向常量的指针常量。既不可以改变他的内存指向,也不可以通过他修改指向内存的内容。
后续
如果大家喜欢这篇文章,欢迎点赞;
如果想看更多C++方面的技术知识,欢迎关注!
网友评论