指针理解

this是一个指针!在类的成员函数中可以使用!
在类的成员函数中会隐含传入此参数!
例如:
  class   A
{
public:
            void   SetNum(const   int);
  private   :
        int   _num
};
void   A::SetNum(const   int   num)
{
    _num   =   num;
}
对于上面的成员函数来说
编译器转换成下面的函数代码:
void   A::SetNum(const   A*   this,const   int   num)
{
    this-> _num   =   num;
}
相信应该可以明白了吧!:)

 

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()这样的内存分配函数一起使用

<script type="text/javascript"></script>

 

 

C语言中函数参数的传递有:值传递,地址传递,引用传递这三种形式。题一为值传递,题二为地址传递,题三为引用传递。

void Exchg1(int x, int y)  
{
	int tmp; 
	tmp=x; 
	x=y; 
	y=tmp; 
	printf("x=%d,y=%d\n",x,y) ;
}
void Exchg2(int *px, int *py)
{
	int tmp=*px; 
	*px=*py; 
	*py=tmp; 
	printf("*px=%d,*py=%d\n",*px,*py); 
}

void Exchg3(int &x, int &y)
{
	int tmp=x; 
	x=y; 
	y=tmp; 

	printf("x=%d,y=%d\n",x,y); 


}

int _tmain(int argc, _TCHAR* argv[])
{
	int a=4,b=6; 
	Exchg1 (a,b) ; 
	printf("a=%d,b=%d\n",a,b) ;
	Exchg2 (&a,&b) ; 
	printf("a=%d,b=%d\n",a,b) ;
	Exchg3 (a,b) ; 
	printf("a=%d,b=%d\n",a,b) ;

 地址传递和引用传递效果一样,但是引用传递不开辟新的内存空间。即x,y的地址指向a,b的地址。

 

 

针概念:
早在本系列第二篇中我就对指针的实质进行了阐述。今天我们又要学习一个叫做指向另一指针地址的指针。让我们先回顾一下指针的概念吧!
当我们程序如下申明变量:
short int i;
char a;
short int * pi;
程序会在内存某地址空间上为各变量开辟空间,如下图所示。
内存地址→6     7  8     9     10     11    12    13     14    15
-------------------------------------------------------------------------------------
…  |     |
  |  |  |  |  |  |  |  
|  
-------------------------------------------------------------------------------------
     |short int i |char a|
  
|short int * pi|
图中所示中可看出:

i
变量在内存地址5的位置,占两个字节。
a
变量在内存地址7的位置,占一个字节。
pi
变量在内存地址9的位置,占两个字节。(注:pi 是指针,我这里指针的宽度只有两个字节,32位系统是四个字节)
接下来如下赋值
:
i=50;
pi=&i;
经过上在两句的赋值,变量的内存映象如下
:
内存地址→6     7  8     9     10     11    12    13  
14     15
--------------------------------------------------------------------------------------
…  |    50
  |  |  |    6   |  |  |  
|  
--------------------------------------------------------------------------------------
     |short int i |char a|
  
|short int * pi|
看到没有:短整型指针变量pi的值为6,它就是I变量的内存起始地址。所以,这时当我们对*pi进行读写操作时,其实就是对i变量的读写操作。如:

*pi=5;   //
就是等价于I=5;
你可以回看本系列的第二篇,那里有更加详细的解说。

二. 指针的地址与指向另一指针地址的指针
在上一节中,我们看到,指针变量本身与其它变量一样也是在某个内存地址中的,如pi的内存起始地址是10。同样的,我们也可能让某个指针指向这个地址。
看下面代码:
short int * * ppi;    //
这是一个指向指针的指针,注意有两个*
ppi=π

第一句:short int * * ppi;——申明了一个指针变量ppi,这个ppi是用来存储(或称指向)一个short int * 类型指针变量的地址。
第二句:&pi那就是取pi的地址,ppi=π就是把pi的地址赋给了ppi。即将地址值10赋值给ppi。如下图:
内存地址→6     7  8     9     10     11    12    13  14    15
------------------------------------------------------------------------------------
…  |    50     |
  |  |  6  |  10  |  
|  
------------------------------------------------------------------------------------
     |short int i|char a|
  
|short int * pi|short int ** ppi|
从图中看出,指针变量ppi的内容就是指针变量pi的起始地址。于是
……
ppi
的值是多少呢?——10

*ppi
的值是多少呢?——6,pi的值。
**ppi
的值是多少呢?——50,I的值,也是*pi的值。
呵呵!不用我说太多了,我相信你应明白这种指针了吧!

三. 一个应用实例
1
设计一个函数:void find1(char array[], char search, char * pa)
要求:这个函数参数中的数组array是以0值为结束的字符串,要求在字符串array中查找字符是参数search里的字符。如果找到,函数通过第三个参数(pa)返回值为array字符串中第一个找到的字符的地址。如果没找到,则为pa0

设计:依题意,实现代码如下。
void find1(char [] array, char search, char * pa)
{
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
   if (*(array+i)==search)
  
{
  
pa=array+i
  
break;
  
}
  
else if (*(array+i)==0)
  
{
  
pa=0;
  
break;
  
}
    }
}
你觉得这个函数能实现所要求的功能吗?

调试:
我下面调用这个函数试试。
void main()
{
   char str[]={“afsdfsdfdf\0”};  //
待查找的字符串
   char a=’d’;   //
设置要查找的字符
   char * p=0;  //
如果查找到后指针p将指向字符串中查找到的第一个字符的地址。
   find1(str,a,p);  //
调用函数以实现所要操作。
   if (0==p )
   {
      printf (“
没找到!\n”);//1.如果没找到则输出此句
   }
   else
   {
      printf(“
找到了,p=%d”,p);  //如果找到则输出此句
   }
}
分析:
上面代码,你认为会是输出什么呢?
运行试试。
唉!怎么输出的是:没有找到!
而不是:找到了,……
明明a值为’d’,而str字符串的第四个字符是’d’,应该找得到呀!
再看函数定义处:void find1(char [] array, char search, char * pa)
看调用处:
find1(str,a,p);
依我在第五篇的分析方法,函数调用时会对每一个参数进行一个隐含的赋值操作。

整个调用如下:
    array=str;
    search=a;
    pa=p;    //
请注意:以上三句是调用时隐含的动作。
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
   if (*(array+i)==search)
  
{
  
pa=array+i
  
break;
  
}
  
else if (*(array+i)==0)
  
{
  
pa=0;
  
break;
  
}
    }
哦!参数pa与参数search的传递并没有什么不同,都是值传递嘛(小语:地址传递其实就是地址值传递嘛)!所以对形参变量pa值(当然值是一个地址值)的修改并不会改变实参变量p值,因此p的值并没有改变(p的指向并没有被改变)

(如果还有疑问,再看一看《第五篇:函数参数的传递》了。)
修正:
void find2(char [] array, char search, char ** ppa)
{
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
   if (*(array+i)==search)
  
{
  
*ppa=array+i
  
break;
  
}
  
else if (*(array+i)==0)
  
{
  
*ppa=0;
  
break;
  
}
    }
}
主函数的调用处改如下:

   find2(str,a,&p);  //
调用函数以实现所要操作。
再分析:
这样调用函数时的整个操作变成如下:
    array=str;
    search=a;
    ppa=&p;    //
请注意:以上三句是调用时隐含的动作。
    int i;
    for (i=0;*(array+i)!=0;i++)
    {
   if (*(array+i)==search)
  
{
  
*ppa=array+i
  
break;
  
}
  
else if (*(array+i)==0)
  
{
  
*ppa=0;
  
break;
  
}
    }
看明白了吗?

ppa
指向指针p的地址。
*ppa的修改就是对p值的修改。
你自行去调试。
经过修改后的程序就可以完成所要的功能了。
看懂了这个例子,也就达到了本篇所要求的目的。

 

 

 

你可能感兴趣的:(JavaScript,设计模式,dos,D语言)