posts - 29,comments - 10,trackbacks - 0
 

一、数据成员指针 

好了,我们现在需要一种指针,它指向MyStruct中的任一数据成员,那么它应该是这样的子:

     int MyStruct::* pMV = &MyStruct::value;
     
//
     int MyStruct::* pMK = &MyStruct::key;

   
     
这种指针的用途是用于取得结构成员在结构内的地址。我们可以通过该指针来访问成员数据:

     int value = pMe->*pMV; // 取得pMevalue成员数据。
     int key = me.*pMK; // 取得mekey成员数据。

   
    
那么,在什么场合下会使用到成员数据指针呢?
   
确实,成员指针本来就不是一种很常用的指针。不过,在某些时候还是很有用处的。我们先来看看下面的一个函数:

  int sum(MyStruct* objs, int MyStruct::* pm, int count)
  {
      
int result = 0;
      
for(int i = 0; i < count; ++i)
          result += objs[i].*pm;
      
return result;
  }

 这个函数的功能是什么,你能看明白吗?它的功能就是,给定countMyStruct结构的指针,计算出给定成员数据的总和。有点拗口对吧?看看下面的程序,你也许就明白了:
     

     MyStruct me[10] =
     {
      {1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20}
     };     
     
int sum_value = sum(me, &MyStruct::value, 10);
     
//计算10MyStruct结构的value成员的总和: sum_value 值 为 110     (2+4+6+8+ +20)
     int sum_key = sum(me, &MyStruct::key, 10);

   //计算10MyStruct结构的key成员的总和:   sum_key 值 为 100       (1+3+5+7+ +19)

     也许,你觉得用常规指针也可以做到,而且更易懂。Ok,没问题:

     int sum(MyStruct* objs, int count)
     {
      
int result = 0;
      
for(int i = 0; i < count; ++i)
       result += objs[i].value;
      
return result;
     }

你是想这么做吗?但这么做,你只能计算value,如果要算key的话,你要多写一个函数。有多少个成员需要计算的话,你就要写多少个函数,多麻烦啊。指针

二、使用动态分配防止局部变量自动删掉

试一下,你能找出下面这段程序的错误吗?
  #include <iostream.h>
  int *pPointer;
  void SomeFunction();
  {
  int nNumber;
  nNumber = 25;  
  //让指针指向nNumber:
  pPointer = &nNumber;
  }
  
  void main()
  {
  SomeFunction(); //pPointer赋值  
  //为什么这里失败了?为什么没有得到25  
  cout<<"Value of *pPointer: "<<*pPointer<<endl;
  }
  这段程序先调用了SomeFunction函数,创建了个叫nNumber的变量,接着让指针pPointer指向了它。可是问题出在哪儿呢?当函数结束后,nNumber被删掉了,
  因为这一个局部变量。局部变量在定义它的函数执行完后都会被系统自动删掉。也就是说当SomeFunction 函数返回主函数main()时,这个变量已经被删掉,但pPointer还指着变量曾经用过的但现在已不属于这个程序的区域。如果你还不明白,你可以再读读这个程序,注意它的局部变量和全局变量,这些概念都非常重要。
  但这个问题怎么解决呢?答案是动态分配技术。注意这在CC++中是不同的。由于大多数程序员都是用C++,所以我用到的是C++中常用的称谓。
   动态分配  
  动态分配是指针的关键技术。它是用来在不必定义变量的情况下分配内存和让指针去指向它们。尽管这么说可能会让你迷惑,其实它真的很简单。下面的代码就是一个为一个整型数据分配内存的例子:  
  int *pNumber;
  pNumber = new int;  
  第一行声明一个指针pNumber。第二行为一个整型数据分配一个内存空间,并让pNumber指向这个新内存空间。下面是一个新例,这一次是用double双精型:  
  double *pDouble;
  pDouble = new double;  
  这种格式是一个规则,这样写你是不会错的。  
  但动态分配又和前面的例子有什么不同呢?就是在函数返回或执行完毕时,你分配的这块内存区域是不会被删除的所以我们现在可以用动态分配重写上面的程序:  
  #include <iostream.h>  
  int *pPointer;  
  void SomeFunction()
  {  // 让指针指向一个新的整型
   pPointer = new int;
  *pPointer = 25;
  }  
  void main()
  {
  SomeFunction(); // pPointer赋值  
  cout<<"Value of *pPointer: "<<*pPointer<<endl;
  }
  通读这个程序,编译并运行它,务必理解它是怎样工作的。当SomeFunction调用时,它分配了一个内存,并让pPointer指向它。这一次,当函数返回时,新的内存区域被保留下来,所以pPointer始终指着有用的信息,这是因为了动态分配。但是你再仔细读读上面这个程序,虽然它得到了正确结果,可仍有一个严重的错误。
  分配了内存,别忘了回收
  太复杂了,怎么会还有严重的错误!其实要改正并不难。问题是:你动态地分配了一个内存空间,可它绝不会被自动删除。也就是说,这块内存空间会一直存在,直到你告诉电脑你已经使用完了。可结果是,你并没有告诉电脑你已不再需要这块内存空间了,所以它会继续占据着内存空间造成浪费,甚至你的程序运行完毕,其它程序运行时它还存在。当这样的问题积累到一定程度,最终将导致系统崩溃。所以这是很重要的,在你用完它以后,请释放它的空间,如:  
  delete pPointer;  
  这样就差不多了,你不得不小心。在这你终止了一个有效的指针(一个确实指向某个内存的指针)。下面的程序,它不会浪费任何的内存:  
  #include <iostream.h>  
  int *pPointer;  
  void SomeFunction()
  {  // 让指针指向一个新的整型
  pPointer = new int;
  *pPointer = 25;
  }  
  void main()
  {
  SomeFunction(); //pPointer赋值
  cout<<"Value of *pPointer: "<<*pPointer<<endl;
  delete pPointer;
  }  
  只有一行与前一个程序不同,但就是这最后一行十分地重要。如果你不删除它,你就会制造一起内存漏洞,而让内存逐渐地泄漏。(译者:假如在程序中调用了两次SomeFunction,你又该如何修改这个程序呢?请读者自己思考)

 

三、一级指针变量与一维数组的关系

int *p    int q[10]         

数组名是指针(地址)常量

p=q;   p+i q[i]的地址

数组元素的表示方法:下标法和指针法,即若p=q, p[i] Û q[i] Û *(p+i) Û *(q+i)

形参数组实质上是指针变量,即int q[ ] Û int *q

在定义指针变量(不是形参)时,不能把int *p 写成int p[];

系统只给p分配能保存一个指针值的内存区(一般2字节);而给q分配2*10字节的内存区

四、指针与二维数组

1)对二维数组 int a[3][4],

a-----二维数组的首地址,即第0行的首地址

a+i-----i行的首地址

a[i] Û *(a+i)------i行第0列的元素地址

a[i]+j Û *(a+i)+j -----i行第j列的元素地址

*(a[i]+j) Û *(*(a+i)+j) Û a[i][j]

a+i=a[i]=*(a+i) =&a[i][0], 值相等,含义不同

a+i   表示第i行首地址,指向行

a[i] Û *(a+i) Û &a[i][0],表示第i行第0列元素地址,指向列

2)二维数组与指向一维数组的指针变量的关系

如有:   int a[5][10](*p)[10];   p = a ;

系统给数组a分配2*5*10个字节的内存区。

系统只给变量p分配能保存一个指针值的内存区(2字节)

数组名a的值是一个指向有10个元素的一维数组的指针常量;

p=a+i 使 p指向二维数组的第i;

*(*(p+i)+j) Û a[i][j] ;

二维数组形参实际上是一个指向一维数组的指针变量,即: fun(int x[ ][10]) Û fun(int (*x)[10])在函数fun中两者都可以有x++;x=x+2;等操作!但在变量定义(不是形参)时,两者不等价;

3)指针数组与二级指针的关系

int **p    int *q[10]        

系统只给p分配能保存一个指针值的内存区;而给q分配10个内存区,每个内存区均可保存一个指针值

指针数组名是二级指针常量;

p=q;   p+i q[i]的地址;

指针数组作形参,int *q[ ]int **q完全等价;但作为变量定义两者不同。

五、指针与字符串

1)字符指针变量与字符数组的分别

char *cp;        char str[20];

字符数组str由若干元素组成,每个元素放一个字符;而指针变量cp中只能存放一个地址值。

char str[20];     str= "I love China!";    (´)

char   *cp;         cp= "I love China!";    (ü)

str是地址常量;cp是地址变量。

cp接受键入字符串时,必须先开辟存储空间。

六、指向函数的指针变量

定义形式: 数据类型 (*指针变量名)(); int   (*p)( );

main()

{ int max(int ,int), (*p)();

   int a,b,c;

   p=max;

   scanf("%d,%d",&a,&b);

   c=(*p)(a,b);

   printf("a=%d,b=%d,max=%d\n",a,b,c);

}

int max(int x,int y)

{ int z;

   if(x>y) z=x;

   else     z=y;

   return(z);

}

 

posted on 2009-06-25 16:18 The_Moment 阅读(407) 评论(0)  编辑 收藏 引用 所属分类: C\C++

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理