什么是指针
变量的内存地址叫指针,存放指针的变量叫指针变量。估计不少人会混淆这2个概念,而且有的书籍资料把“指针变量”称为“指针”。
数据的存储方式
程序中的数据都会占用一块内存空间,不同数据类型占用的内存大小不同。比如char、bool是1个字节、short是2个字节、int是4个字节等。
内存是有地址的,计算机是通过内存地址来访问的。在计算机中,1个地址代表1个字节。我们常说的8位、16位、32位、64位,指的是地址的长度。即地址有几个bit位。
比如:
(1)8位机表示地址长度是8个bit,2进制的11111111转成16进制是FF,所以地址范围是0x00 -- 0xFF。这样就有256个地址,即内存的大小是256个字节。
(2)32位机表示地址长度是32个bit,所以地址范围是0x0000 0000 - 0XFFFF FFFF。有2^32个地址,即内存的大小是4G。
假设现在定义了2个变量:int i, int j,因为每个变量占4个字节内存,则这2个变量在内存中的位置大概是像下面这样的。
数据的读取方式
知道了变量的地址和变量的类型后,就可以这样访问变量int i了:
(1)先找到存放变量的首地址,比如0x0000 0001;
(2)从这个地址开始取4个字节的数据。
我们可以用代码来演示一下:
class A {
public:
int i = 11;
};
int main()
{
A a;
int* i = (int*)&a;
printf(" 变量i的值: %d\n", *i);
return 0;
}
我们先用&a取到了对象a的首地址,根据C++对象模型我们知道这个首地址也是变量i的首地址,所以从这个地址开始取int类型长度的数据就是变量i的值。
通过地址我们能找到所需的变量,也可以说地址“指向”该变量。因此,这个地址也被称为指针,即英文pointer。所以我们在C++中所说的指针其实是一个地址。
指针也需要有地方存储,这个存储指针的变量就叫指针变量,即存储指针的变量。
指针变量
存放指针的变量叫指针变量,定义指针变量的一般形式为:
类型名* 指针变量名;
int* pi; //也可以这么写:int *pi; 或 int * pi;
float* pf; //也可以这么写:float *pf; 或 float * pf;
另外,也可以在定义指针变量时对它进行初始化。
int i = 12;
float f = 12.0
int* pi = &i;
float* pf = &f;
建议在定义指针变量的同时进行初始,如果此时指针没法指向有效的地址,可以把NULL赋给指针。比如:
int* pi = NULL;
我们可以用下面的图来表示指针变量和其所指向的变量的对应关系。 关于指针变量,我们要注意这几个问题:
(1)指向int数据的指针类型表示为:int*,读作”指向int的指针“或”int指针“。int*、char*、float*分别读作int指针、char指针、float指针,它们是3种不同类型的指针。
(2)int* pi 表示一个指向int型变量的指针变量。它可以指向任何int型变量,但不能指向其他类型。
(3)指针变量前面的“”号表示该变量为指针变量。指针变量名是pi、pf,而不是pi、*pf。在C语言中,
*pi代表指针变量所指向的变量的值,也就是int i的值;同理,*pf代表float f的值。
比如在定义了指针变量后,应该把地址赋给pi、pf,而不是*pi、*pf:
int i = 12;
float f = 12.0
int* pi;
float* pf;
//正确的赋值方式
pi = &i;
pf = &f;
//下面的赋值是错误的
*pi = &i;
*pf = &f;
(4)一个指针变量包含2个重要的信息:地址和数据类型。地址确定了变量在内存中的位置,数据类型确定了变量所占内存的大小。
指针相关的几个概念
假如pi是int型的指针变量,它指向变量a,下面我们来看几个概念。
int a = 2;
int* pi = &a;
(1)int* pi = &a;
把变量a的地址赋给指针pi。指针变量pi指向变量a,pi的值是变量a的地址。
(2)*pi = 100;
把整数100赋给pi指向的变量,即把100赋给变量a,a = 100。
(3)printf("%d\n", *pi);
打印pi所指向的变量的值,即打印变量a的值。
(4)printf("%p\n", pi);
打印指针变量pi的值,即打印变量a的地址。
(5)printf("%p\n", &pi);
打印指针变量自身的地址。
(6)&*pi
从右往左读,*pi表示指针变量pi所指向 变量,即a;&a表示取变量a的地址,即指针变量pi。
(7)*&a
先计算&a,即pi;*pi表示变量a。
(8)(*pi)++
先计算*pi,即a;这条语句的意思是a++。
(9)*pi++
从右往左读,先pi++,再*,所以等价于*(pi++)。即先返回*pi的值,然后指针再+1。
因为pi是指针变量,这里的pi++是什么意思呢?
pi++表示指针变量向下移动1次,假如pi指向的是整型变量,则pi++就是往下移动4个字节。当然,这可能会读到非法内存而导致程序出错。
class A {
public:
int i = 4;
int j = 5;
};
int main()
{
A a;
int* pi = &a.i;
int c = *pi++;
std::cout << c << std::endl;
std::cout << *pi << std::endl;
return 0;
}
常量和指针
常量指针:指向常量的指针变量。
const int* p = &a;
因为指针变量的定义是这样的:数据类型* 指针变量,所以这里的数据类型是:const int,即常量int。所以指针指向的这个值不能被修改,但指针p可以指向其他int类型的数据。
int a = 1;
const int* p = &a;
*p = 2; //报错. p指向的值不能被修改
int b = 2;
p = &b; //正确. p可以指向其他int
指针常量:指针是一个常量,它的指向不能被修改。
int* const p = &a;
指针变量是const p,所以这个指针变量是常量,它的指向不能被修改。