参考:http://www.jizhuomi.com/software/78.html
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。
我们使用的内存的基本存储单位是字节,一个字节由8个二进制位组成。每个字节都会按照一定的规则编号,这个编号就是该字节存储单元的地址。计算机就是利用这种编号也就是字节存储单元的地址来定位内存进行数据读写的。
我们在访问内存中的数据时,有两种方式,一种是通过变量名,一种是通过地址。我们声明的每个变量都是占据内存空间的,char型占1个字节,float型占4个字节。而内存空间的分配是在什么时候呢?全局变量、static静态变量等静态生存期变量在程序开始运行之前(编译时)就被分配了内存空间,动态生存期的变量是在变量声明时分配内存空间的,然后变量名也代表了分配的空间。但是有时候没有变量名可用或者很不方便,例如,在动态内存分配时就没有变量名可以用;调用函数传递很多参数时,就不可能一个一个的通过变量名传递,而是需要用地址传递。
指针类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。
int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]
指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。
地址相关运算--“*”和“&”
int *ptr; //指针所指向的类型是int char *ptr; //指针所指向的的类型是char int **ptr; //指针所指向的的类型是 int * int (*ptr)[3]; //指针所指向的的类型是 int()[3] int *(*ptr)[4]; //指针所指向的的类型是 int *()[4]
“*”在地址运算中叫做指针运算符,表示指针指向的变量的值,是一元操作符,例如,如果p是一个int型的指针,则*p表示p指向的int型数据的值。“&”在地址运算中叫做取地址运算符,也是一个一元操作符,用来获取一个对象的地址,例如,有一个变量i,&i就表示变量i的存储单元地址。“*”出现在声明语句中被声明的变量名之前时,表示声明的是指针,例如,int *p;。“*”出现在声明语句的初值表达式中或者执行语句中时,表示指针指向的对象的内容,例如,int i=*p; cout<<*p;。“&”出现在声明语句中被声明的变量名之前时,表示声明的是引用,例如,int &rf;。“&”出现在声明语句的初值表达式中或者执行语句中时,表示取对象的地址
指针的赋值
当我们声明了一个指针之后,这个指针变量中没有存储任何确定的地址值,而是一个随机整数。也就是它指向的地址是不确定的,有可能它指向了系统的重要数据,这时候我们如果修改了它指向地址的值可能会引起想象不到的系统问题。所以指针声明以后要先赋值才可以引用。
给指针赋值可以有下面两种方法:
赋给指针变量的值必须是地址常量(比如数组名)或地址变量,但一定不能是非0整数。 给指针赋值为0时表示该指针是一个空指针,它不指向任何地址,比如,int *p=0;。为什么会把指针声明为空指针呢?我们在声明一个指针时没有给它赋值,这时它是一个随机的值,在给它赋确定的地址值之前如果我们使用了它,就可能会访问到重要的内存地址并破坏此地址的数据,造成严重后果,所以我们在软件开发中一般先将指针设为空指针。int a[5]; // 声明一个整型数组 int *p1=a; // 声明指针p1,并用数组首地址a来初始化p1 int *p2; // 声明指针p2 p2=a; // 将数组首地址a赋值给指针p2
数组名就是数组的首地址,所以可以用数组名来赋值给指针。
举个例子:
#include <iostream> int main(void) { using namespace std; int *p; //声明int型指针p int i=6; //声明int型数i,赋值为6 p=&i; //取i的地址赋给p cout<<"Value: i="<<i;//输出int型数的值 cout<<", *p="<<*p<<endl; cout<<"Addresses: &i= "<<&i;//输出i的地址 cout<<", p: p= "<<p<<endl;//输出p的值 *p=*p+1; cout<<"Now i= "<<i<<endl; return 0; }
输出的结果为
注意:int *p=&i,是初始化指针p,将其值定义为&i,并不是初始化*p,另外给指针赋值时,并不能直接在那放个整数,例如 int*p;p=0xB8000000;这个左边的p是一个指向int的指针,不一定是int型,可以把它赋给地址,但是右边是一个整数,并不能代表其为一个地址,,最好的办法就是强制类型转换p=(int *) 0xB8000000;
我们可以声明指向常量的指针,这时候指针本身的值可以改变,也就是指针可以指向其他对象,但是我们不能通过指针改变它指向的值。例如:
我们还可以声明指针常量,这时候指针本身的值不能改变,例如:const char *name="Tom"; //指向常量的指针 char s[]="Lili"; name=s; //正确,name本身的值可以改变 *name=’a’; //编译时指出错误,不能通过name修改指向的对象
int a=1; int b=2; int *const p=&a; // 声明指针常量p p=&b; // 错误,不能改变指针常量p的值
我们进行指针赋值时可以将某个指针的值赋给相同类型的另一个指针。但是有一种特殊类型的指针,可以用任意类型对象的地址为之赋值,这就是void类型指针。我们在使用void类型的指针访问数据时需要进行强制类型转换。举个例子:
<span style="font-family:FangSong_GB2312;"> void *p; int *p1; int a; void main() { p=&a; // void类型的指针p指向整型变量a p1=(int*)p; // 用强制类型转换的方式将void指针p的指针赋给int型指针p1 }</span>