指针应该是C/C++最具有争议的数据类型,这从其他高级语言:C#、JAVA等等都抛弃指针而追求更强的安全性来看,指针应该具有特殊的功能。
指针变量
指针变量是指针的缩成,其实也就是一种数据类型:整型 int可以保存整数类型的值,指针则是可以保存 “内存地址” 的一种新的数据类型。看起来并没有太多特殊的地方。
普通类型的变量存放在内存空间,有它的内存地址;数组类型、函数、指针(它自己)、结构体、对象等等都存放在内存空间,这 就意味着指针其实都可以保存它们的地址。
保存数据(变量)的地址,就好像拿到了打开门的钥匙,修改普通变量的值、调用函数的功能、调用对象的成员函数等等应该就是理所当然的。
如果再加上C/C++中的强制类型转换,本来只能保存某种类型地址的指针,可以强转成其他类型,那么这把钥匙是不是有点“万能”的感觉?
语法:
数据类型 * 指针变量名;
* 是指针变量特定的标识符,数据类型表明指针可以保存申明类型的变量地址。
int *p; float *q; char *k; 等等分别可以保存int、float、char类型变量的地址。
两个操作符: & 和 * (前面已经提及)
int a; int *p=&a; //取出定义的a变量地址,保存在指针p中,称为p指向了a
*p=5; //这个* 是操作符,而不是定义的标识符,根据p的地址取内容,也就是a = 5
int *p=&a; 定义指针的同时初始化,所有没有初始化的指针称为“野指针”,这个杀伤力比没有初始化的变量大得多,所以养成一个习惯,如果无法马上就初始化指针,定义时指定为NULL值
int *p=NULL; //空指针
指针与引用要区别:引用是别名,可以实现局部变量跨函数使用;指针则保存变量的地址;
#include <iostream>
#include <stdio.h>
using namespace std;
void fun1(int &a,int &b)
{
int t;
t=a;
a=b;
b=t;
}
void fun2(int *a,int *b)
{
int t;
t=*a;
*a=*b;
*b=t;
}
int main()
{
int x,y;
x=3,y=4;
fun1(x,y);
fun2(&x,&y);
return 0;
}
区别很明显,一个是函数定义时候在形参上使用 & 表明是引用;另外一个是调用的时候实参用操作符 & 取地址,定义则用指针(指针存放地址)。
二维指针
指向指针的指针,那么就是二维指针了。语法:
数据类型 ** 指针变量名;
int ** p; float **q; char **k; //与一维指针类似,区别在于保存的是一维指针的地址
int main()
{
int a; int *p= &a;
int **q=&p;
**q=5;
cout<<a<<endl;
*p=10;
cout<<a<<endl;
return 0;
}
两个**可以连用,两个&&不行:int **q=&&a;错误。或者说,直接对一个变量取两次地址操作是错误的!
拓展
1、在32位地址程序中,所有的指针变量的大小都是4个字节:地址是32位,保存它正好4个字节。例:char a;是一个字节 char *a;则是四个字节。
2、指针也可以是局部、全局、外部以及静态的;
3、定义指针就是分配了一个内存空间,这个内存空间可以保存局部变量的地址,也可以保存全局变量或者其他类型的地址;
4、指针和数组名的区别在于,数组名是首地址,是常量,而指针是变量;
5、指针的使用并不复杂,难度在于它与其他数据类型相互配合使用;指针的类型强制转换可能会出现问题,也可能解决问题时带来新的思路;
6、C/C++中内存空间的管理是由程序员完成,这需要对指针更好的理解。