指针的描述(以下的所有地方都基于C89标准):
指针与数组,结构,联合等一样也是一种数据对象,其值是另外一个对象的地址(这是重点,指针变量里面保存的内容是另外一个对象的地址)。
“指针”得名于这样的事实:其内容“指向”另外一个对象。指针可以指向任何类型(完整类型的或者不完整类型)的对象。一个指针还可以指向其他指针(也就是指向指针的指针),可以实现“多重间接寻址”。更为重要的是指针还可以指向一个函数(入口地址)。当然,一个指针也可以什么地方也不指向(空指针)。
一个指针并不能指向各种类型的对象(在一定的条件下,可以进行强制类型转换),即并不是各种对象(变量)的地址都可以存储到任一指针对象(变量)中,和其他对象一样,每一个指针对象也有一个确定的类型。说起来好像有点拗口,例如:具有指向字符的指针类型的对象不能用于存储整数对象的地址(即不能把整数对象的地址赋值给指向字符的指针变量,强制类型转换除外),反之亦然。
指针类型是由指向对象的类型确定的,一种指针类型的所有对象(变量)所指向的对象的类型必须是相同的。指针变量在使用之前必须进行说明,其说明的一般形式是:
<指向类型> * <变量标识符>
例如,变量说明:
int *intptr; //一个指向int类型的指针变量intptr
char *charptr; //一个指向char类型的指针变量charptr
char ** ptrtochar;//一个指向char *类型的指针变量ptrtochar
指针变量的长度问题:一个指针变量的取值范围(长度)不是固定的,但是其范围总是应该可以覆盖机器可用内存的地址(这是决定指针变量长度的重点)。比如在一些小RAM的4位机上,可能指针只有11bits,在x86上32bits(也就是早期PC最大内存空间4GB=0xFFFFFFFF的缘故),在64位机上指针就变成了64bits
每一种类型的指针对象都有一个特殊的值NULL。在stddef.h中空指针NULL定义如下
#define NULL 0 /* null pointer constant. */
空指针表示指针不指向任何位置。该值是有别于指向具体对象或者函数的指针的特殊值。
指针的指针变量:是指向另一个指针的地址的一种变量类型。
先看看最基本的,比较单一的,也是常用的指针定义和其在内存的存储内容。
这是我的一段基本测试代码,用来说明指针的最基本原理和用法,虽然只是演示了整数类型的使用,对其他类型具有相同的原理,请举一反三,开发环境基于keil MDK 5.26。
int TestPointer(void)
{
int value; //定义一个整型变量
int result; //定义一个整型变量
int *pInt; //定义一个指向整型类型的指针变量
int ** ppInt; //定义一个指针的指针类型的变量
int *** pppInt; //定义一个指针的指针的指针类型的变量
int addr;
DebugPrintf(" 指针测试:\r\n");
addr = (int)&value;
DebugPrintf("value 的地址:0x%08x\r\n",addr);
addr = (int)&result;
DebugPrintf("result 的地址:0x%08x\r\n",addr);
addr = (int)&pInt;
DebugPrintf("pInt 的地址:0x%08x\r\n",addr);
addr = (int)&ppInt;
DebugPrintf("ppInt 的地址:0x%08x\r\n",addr);
value = 0x12345678; //赋值一个整型变量
pInt = &value; //指针变量初始化,用value的地址赋值
result = *pInt; //通过指针变量pInt取整型变量value的值
DebugPrintf("result = :0x%08x\r\n",result);
ppInt = &pInt; //取指针变量的地址赋值给指针的指针变量
result = (int)*ppInt;
//取的是指针变量ppInt的内容(即指针变量pVal的地址)
//这里使用了一个技巧,强制类型转换。因为*ppInt得到的是一个指针类型变量的值,
//所以不能直接赋值给整型变量,但是ARM的指针类型和整数类型的数据长度是一样的
//所以我们把这个地址可以转换为整型数值。
DebugPrintf("pInt的内容(value的地址) = :0x%08x\r\n",result);
result = **ppInt; //通过指针的指针变量ppInt去取整型变量value的值
DebugPrintf("通过指针的指针**ppInt获取的值 result = :0x%08x\r\n",result);
pppInt = &ppInt;
result = (int)*pppInt; //获取指针的指针的内容(pInt的地址)
DebugPrintf("通过指针的指针的指针 = :0x%08x\r\n",result);
return result;
}
指针的基本定义和使用参考代码里面的注释理解。
我们看看输出的结果,对照代码就比较容易理解。
- 前面1-5行分别输出了几个变量在内存中的地址,可以看到,每一个变量占用四个字节,也就是32位长度
- 第6行输出了int类型变量result的值。
- 第7行显示了一个指针变量的内容,也就是变量result的地址。和前面第1行打印的一致。
- 第8行显示了通过指针的指针的变量去访问result的方式。
- 第9行展示了一个不常用的,诡异的,匪夷所思的,但是C语言允许而且编译器支持的类型:指针的指针的指针,我们获得了正确的结果。你如果愿意还可以一直定义下去,比如int **** pppInt;一般我们不使用这种晦涩的定义方式,除了耍酷和证明编译器支持以外,平时不要去使用这种难以理解的方式。
原创文章,欢迎转载,请注明来源,未经书面允许,请勿用于商业用途。