答案:首先,到底什么是指针呢?
其实,指针就是一个无符号整形数值(当然,指针也可以是负数,不过没有任何意义)
其实就是一个指向内存中某个位置的地址号,就象你家的门牌号一样.
在DOS和16位操作系统中,指针都是16位的,在WIN32系统中,有两种指针,16位短指针和32位的长指针.
而在WINDOWS程序中,指针同样有真实地址指针和进程虚拟指针两种.
为什么要使用指针?
我刚学C语言的时候,也为这个问题而迷惑,到底为什么要用指针呢?指针的好处在哪?
下面我举几个实际编程中遇到的情况来说明:
参数的传递.当我们想要在子函数中修改传递进去的参数的值(而不是他的拷贝值),那么我们必须传递指针.在C++中有了引用,但
其实引用的本质就是指针.
动态的内存分配.有时候,我们不可能可以预计我们到底需要多少个变量,这个时候我们就需要动态的来创建变量.就需要用到指针.
数据结构.数据结构是离不开指针的,无论是链表,树,还是图,都是离不开指针的.如果你想编写一个出色的存储查找程序
你就必须使用指针,象我们平时用到的几乎所有数据库(ACCESS,SQL,ORACLE...)的内部存储查找结构就是如此.
WINDOWS消息机制.WINDOWS消息机制函数只传递两个参数,WPara和LPara,但却能满足实现WINDOWS成百上千种不同的消息.
为什么呢,因为使用了指针,WPara是一个16位短整型,LPara是一个32位长整形,这两个参数就是指针(一个是16位指针,一个是
32位指针).WINDOWS使用指针来传递消息函数所需要的任何参数.这也只有指针能做到.(想想为什么)
WINDOWS线程函数.和WINDOWS消息函数很相似,WINDOWS线成函数只提供一个参数PVOID(VOID型指针)作为你所能想到的任何线程函数
的参数.没有指针,你能做到吗?
还有很多必须使用指针的情况,无法在这一一列举.
关于指针的类型
指针也有类型的,指针的类型同样支持编译器内部定义类型(如INT,CHAR等)和用户自定义类型(如STRUCT等).
在C中,指针的类型到底有什么用呢?其中最重要的一点就是指针的加减运算.
如果一个指针i的值是10000,那么如果执行i++,或者i+n,结果将由指针的类型来决定.值等于 10000+sizeof(指针类型) 或者 10000+sizeof(指针类型)*n.
换句话说,对指针的加减n操作,就是相当于将指针向后或向前移动n个该类型单位.
数组的实现正是基于该机制的.一般编译器遇到数组后,比如a[5],实际上的操作是取指针a+5所指向的值.
另外,直接使用指针加减法要比使用数组下标速度更快.任何数组都是指针.
指针的加减法以外的其他运算操作,一般情况下是没有任何意义的.
而在C++中,由于考虑到程序稳定性,安全性的问题,对指针类型的自动转换有严格的限制,只允许将非VOID类型的指针
自动转换为(或者赋值)VOID类型的指针,而不允许将VOID类型的指针或其他类型的指针自动转换(或者赋值)
给其他非VOID型指针.
关于指针的初始化
如果定义了一个指针,我们没有初始化的话,那么该指针可能是任意值(甚至指向你操作系统的某个核心块)
所以,没有初始化的指针是极为不安全的,绝大多数情况下也是无易做图常使用的.
所以,象下面这些程序都会导致程序运行出错,却能编译成功(我们称为运行期错误).
char* p;
char* m;
realloc(p,5);
scanf("%s",m);
数组也是指针,那么为什么我们能把数组象常量那样定义,而不用初始化呢
比如 char s[6];
scanf("%s",s);
这是因为,编译器对数组的处理是先分配内存,然后把内存的地址给数组指针,这实际上就是已经初始化了.象上面
那段程序,编译器相当于做了下面的工作:
char *s=malloc(6); //malloc(6)函数分配一个6Byte的内存,返回给s
scanf("%s",s);
但如果你在输入S的时候,输入的字符大于5,同样会导致运行期错误.(想想为什么?)
这里还要注意一个问题,如果我们写成
char s[6];
s="abcde";
那么其实是一个完全不同的概念.
任何字符串都是指针! "123","abcde",当程序中出现这样的字符串的时候,你千万不要认为它是一串值,其实它是一个指针.
编译器遇到 "abcde" 等字符串后,就会分配一个字符串长度加1的内存空间(这个1是'\0'),然后把指针值返回给s.
所以,假设一开始char s[6]的s指针值是10000的话,执行s="abcde",s就是一个完全不同的值了,指向了一个完全不同的内存块.
所以, char* s;
s="abcde";
是完全正确的.
但是,
char* s;
char* s1;
s="abcde";
s1="12345";
memcpy(s,s1,6);
却也会导致一个运行期错误,这是为什么呢?
这里我们又必须再次讨论编译器对字符串的处理了.编译器遇到字符串后给他们分配的内存是一个只读内存,也就是说不能往里面写东西,只能读取,
所以当我们将s1内存块的值COPY到s的时候,就会导致错误
指针使用比较灵活,如果说它的好处,根据我平时编程时的感受,大概有这么几点:
1.在数据传递时,如果数据块较大(比如说数据缓冲区或比较大的结构),这时就可以使用指针传递地址而不是实际数据,即提高传输速度,又节省大量内存。
2.数据转换,利用指针的灵活的类型转换,可以用来做数据类型转换,比较常用于通讯缓冲区的填充,比如说,一个数据缓冲区char buf[100],如果其中buf[0,1]为命令号,buf[2,3]为类型,buf[4~7]为某一数值,类型为int,就可以使用如下语句进行赋值:
*(short*)&buf[0]=cmdID;
*(short*)&buf[2]=type;
*(int*)&buf[4]=value;
3.字符串指针,是使用最方便,且常用的。
4.函数指针,形如:#define PMYFUN (void*)(int,int),可以用在大量分支处理的实例当中,如某通讯根据不同的命令号执行不同类型的命令,则可以建立一个函数指针数组,进行散转。
5.在数据结构中,链表、树、图等大量的应用都离不开指针。
可以更好的操作内存~
可以当作计数器用
可以更方便的操作数组
无需知道具体的位置等等,反正挺好的
比较灵活啊使用起来,不过没有学好指针的话会很危险,没有学会指针就不用说是个程序员这是一个我认识的人对我说学习指针时候的第一句话!
指针是把双刃剑,用的好就能很灵活,如果用不好就会引发很严重的问题。
上一个:求助:谁有C++的多边形扫描线填充算法的源代码!
下一个:有人知道C++程序及其语言的发展历史么?