指针详解
1、什么是指针
指针是一种数据类型,与其它的数据类型不同的是指针是一种“用来存放地址值的”变量。举一个简单的例子:
如果定义了一个整型变量,根据整型变量的特点,它可以存放的数是整数。
如:int a; a=100; 这样就把整型常量赋给了变量a。但是如果写成这样:a=123.33;就会出问题,最后输出变量a的值结果是123。现在说到指针,其实地址值也是一个整型数,如某某变量的地址值为36542,说明这个变量被分配在内存地址值为36542的地方。能不能这样进行推理,既然地址值也是整型数,整型变量正好可以用来存放整型数,那不是一个整型变量可以用来存放地址的值吗。程序写成下面这样:
int a,b;
a=&b;
很明显,这样写是错误的。原因在于不能简单地把地址理解为整型数。
应有这样的对应关系: 地址值<--->指针; 整型数<--->int 型变量。
所以有这样的说法:“指针就是地址”(指针就是存放地址值的一种数据类型)
下面是一段正确的程序:
int a,*p;
p=&a; /*把变量a的地址值赋给指针p*/
2、什么是void指针
void的意思就是“无值”或“无类型”。void指针一般称为“通用指针”或“泛指针”。之所以有这样的名字是因为使用void指针可以很容易地把void指针转换成其它数据类型的指针。例如在为一个指针分配内存空间的时候:
int *p;
p=(int *)malloc(......); 本来函数malloc的返回值是void类型,在这里通过在前面加上一个带括号的int*就把void*类型转换成了int*类型。
所以不能简单的把void看成“无”的意思。void数据类型是一种很重要的数据类型。
3、指针可以相加减吗
可以相互加减。但是一定要作有意义的运算。当二个指针指向同一个数组的时候,它们相加减是有意义的。如果二个指针分别指向二个不同的数组,那么指针之间的相加减就没有什么意义。指向同一个数组时,其相加减的结果为二个指针之间的元素数目。
4、什么是NULL指针
NULL指针是不指向任何一个地址的指针。这样的指针一般是允许的。当一个指针为NULL的时候,不要对它进行存取。
5、什么是“野”指针
野指针是不由程序员或操作者所能控制的指针。当在一个程序里面定义了一个指针而又没有给这个指针一个具体地址指向的时候,这个指针会随意地指向一个地址,这样的指针就是一个野指针。如果这个地址后面的内存空间没有什么重要的数据则不会造成不好的后果,但是一旦这里面存放了有用的数据,那么这些数据随时都有被野指针存取的危险,如果这样,数据就会被破坏,程序也会崩溃。所以在程序里面是一定要禁止任何野指针的存在。当定义了一个指针的时候,要马上给这个指针分配一个内存地址的指向。这样程序才不会因为指针而出现意外。
6、NULL的值是什么
NULL不是被定义为0就是被定义成(void *)0,这二种值基本上是一样的。
如有这样的语句: if(p==NULL) 或者写成 if(p==0) 其作用是一样。
7、什么是“内存泄漏”
当定义了一个指针的时候,立即要为这个指针分配一个内存空间。这只防止了野指针的产生。当一个指针使用完毕要立即释放掉这个指针所占用的内存空间---这有二方面的意义: 1)避免了内存空间的泿费; 2)防止了内存泄漏。为什么会产生内存泄漏:如果没有及时释放掉指针所占用的内存空间,而在下次使用这个指针时又给这个指针分配了内存空间,这样的次数一多,内存空间就慢慢被消耗掉了。所以形象地称这种现象为内存泄漏。
如下面这样一个程序:
void *p;
for(;;)
p=malloc(20); /*这20个字节的内存空间是随意指定的*/
这样的一个小程序,大家不要随便运行它。你可以在集成环境中单步调试运行,可以看一下每步运行后的结果。可以看到,每一次循环都会“吃掉”20个字节的内存,无数次之后,再多的内存也慢慢地“泄漏”,最后没有内存可用就死机。(与这个程序配合需要一段检测整机总的内存容量的程序,以观察内存总量的变化。这里虽然没有这一段程序,但是看得到每次分配的内存地址值是不相同的)
8、near指针和far指针
在DOS下(实模式)地址是分段的,每一段的长度为64K字节,刚好是16位(二进制的十六位)。
near指针的长度是16位的,所以可指向的地址范围是64K字节,通常说near指针的寻址范围是64K。
far指针的长度是32位,含有一个16位的基地址和16位的偏移量,将基地址乘以16后再与偏移量相加,(所以实际上far指针是20位的长度。)即可得到far指针的1M字节的偏移量。所以far指针的寻址范围是1M字节,超过了一个段64K的容量。例如一个far指针的段地址为0x7000,偏移量为0x1244,则该指针指向地址0x71224.如果一个far指针的段地址是0x7122,偏移量为0x0004,则该指针也指向地址0x71224。
如果没有指定一个指针是near或far,那么默认是near。所以far指针要显式指定。far指针工作起来要慢一些,因为每次访问一个far指针时,都要将数据段或程序段的数据交换出来。另外,far指针的运算也比较反常,例如上面讲到的far指针指向同一个地址,但是比较的结果却不相同。
9、什么时候使用far指针
当使用小代码或小数据存储模式时,不能编译一个有很多代码或数据的程序。因为在64K的一个段中,不能放下所有的代码与数据。为了解决这个问题,需要指定以far函数或far指针来使用这部分的空间(64K以外的空间)。许多库函数就是显式地指定为far函数的形式。far指针通常和farmalloc()这样的内存分配函数一起使用
指针是一种数据类型,与其它的数据类型不同的是指针是一种“用来存放地址值的”变量。举一个简单的例子:
如果定义了一个整型变量,根据整型变量的特点,它可以存放的数是整数。
如:int a; a=100; 这样就把整型常量赋给了变量a。但是如果写成这样:a=123.33;就会出问题,最后输出变量a的值结果是123。现在说到指针,其实地址值也是一个整型数,如某某变量的地址值为36542,说明这个变量被分配在内存地址值为36542的地方。能不能这样进行推理,既然地址值也是整型数,整型变量正好可以用来存放整型数,那不是一个整型变量可以用来存放地址的值吗。程序写成下面这样:
int a,b;
a=&b;
很明显,这样写是错误的。原因在于不能简单地把地址理解为整型数。
应有这样的对应关系: 地址值<--->指针; 整型数<--->int 型变量。
所以有这样的说法:“指针就是地址”(指针就是存放地址值的一种数据类型)
下面是一段正确的程序:
int a,*p;
p=&a; /*把变量a的地址值赋给指针p*/
2、什么是void指针
void的意思就是“无值”或“无类型”。void指针一般称为“通用指针”或“泛指针”。之所以有这样的名字是因为使用void指针可以很容易地把void指针转换成其它数据类型的指针。例如在为一个指针分配内存空间的时候:
int *p;
p=(int *)malloc(......); 本来函数malloc的返回值是void类型,在这里通过在前面加上一个带括号的int*就把void*类型转换成了int*类型。
所以不能简单的把void看成“无”的意思。void数据类型是一种很重要的数据类型。
3、指针可以相加减吗
可以相互加减。但是一定要作有意义的运算。当二个指针指向同一个数组的时候,它们相加减是有意义的。如果二个指针分别指向二个不同的数组,那么指针之间的相加减就没有什么意义。指向同一个数组时,其相加减的结果为二个指针之间的元素数目。
4、什么是NULL指针
NULL指针是不指向任何一个地址的指针。这样的指针一般是允许的。当一个指针为NULL的时候,不要对它进行存取。
5、什么是“野”指针
野指针是不由程序员或操作者所能控制的指针。当在一个程序里面定义了一个指针而又没有给这个指针一个具体地址指向的时候,这个指针会随意地指向一个地址,这样的指针就是一个野指针。如果这个地址后面的内存空间没有什么重要的数据则不会造成不好的后果,但是一旦这里面存放了有用的数据,那么这些数据随时都有被野指针存取的危险,如果这样,数据就会被破坏,程序也会崩溃。所以在程序里面是一定要禁止任何野指针的存在。当定义了一个指针的时候,要马上给这个指针分配一个内存地址的指向。这样程序才不会因为指针而出现意外。
6、NULL的值是什么
NULL不是被定义为0就是被定义成(void *)0,这二种值基本上是一样的。
如有这样的语句: if(p==NULL) 或者写成 if(p==0) 其作用是一样。
7、什么是“内存泄漏”
当定义了一个指针的时候,立即要为这个指针分配一个内存空间。这只防止了野指针的产生。当一个指针使用完毕要立即释放掉这个指针所占用的内存空间---这有二方面的意义: 1)避免了内存空间的泿费; 2)防止了内存泄漏。为什么会产生内存泄漏:如果没有及时释放掉指针所占用的内存空间,而在下次使用这个指针时又给这个指针分配了内存空间,这样的次数一多,内存空间就慢慢被消耗掉了。所以形象地称这种现象为内存泄漏。
如下面这样一个程序:
void *p;
for(;;)
p=malloc(20); /*这20个字节的内存空间是随意指定的*/
这样的一个小程序,大家不要随便运行它。你可以在集成环境中单步调试运行,可以看一下每步运行后的结果。可以看到,每一次循环都会“吃掉”20个字节的内存,无数次之后,再多的内存也慢慢地“泄漏”,最后没有内存可用就死机。(与这个程序配合需要一段检测整机总的内存容量的程序,以观察内存总量的变化。这里虽然没有这一段程序,但是看得到每次分配的内存地址值是不相同的)
8、near指针和far指针
在DOS下(实模式)地址是分段的,每一段的长度为64K字节,刚好是16位(二进制的十六位)。
near指针的长度是16位的,所以可指向的地址范围是64K字节,通常说near指针的寻址范围是64K。
far指针的长度是32位,含有一个16位的基地址和16位的偏移量,将基地址乘以16后再与偏移量相加,(所以实际上far指针是20位的长度。)即可得到far指针的1M字节的偏移量。所以far指针的寻址范围是1M字节,超过了一个段64K的容量。例如一个far指针的段地址为0x7000,偏移量为0x1244,则该指针指向地址0x71224.如果一个far指针的段地址是0x7122,偏移量为0x0004,则该指针也指向地址0x71224。
如果没有指定一个指针是near或far,那么默认是near。所以far指针要显式指定。far指针工作起来要慢一些,因为每次访问一个far指针时,都要将数据段或程序段的数据交换出来。另外,far指针的运算也比较反常,例如上面讲到的far指针指向同一个地址,但是比较的结果却不相同。
9、什么时候使用far指针
当使用小代码或小数据存储模式时,不能编译一个有很多代码或数据的程序。因为在64K的一个段中,不能放下所有的代码与数据。为了解决这个问题,需要指定以far函数或far指针来使用这部分的空间(64K以外的空间)。许多库函数就是显式地指定为far函数的形式。far指针通常和farmalloc()这样的内存分配函数一起使用