原文地址:http://www.cnblogs.com/processakai/archive/2012/04/04/2431946.html
错误的地方带查证:
一、 数组的指针、指针数组以及指向指针的指针 考虑数组的指针的时候我们要同时考虑类型和维数这两个属性。换一句话,就是说一个数组排除在其中存储的数值,那么可以用类型和维数来位
一、数组的指针、指针数组以及指向指针的指针
考虑数组的指针的时候我们要同时考虑类型和维数这两个属性。换一句话,就是说一个数组排除在其中存储的数值,那么可以用类型和维数来位置表示他的种类。 A)一维数组 int a[10]; int *p; p=&a[0]//和p=a是等价的: (1) p[i]和a[i]都是代表该数组的第i+1个元素; B)多维数组
对照这个图,如下的一些说法都是正确的(对于a[4][6]): a是一个数组类型,*a指向一个数组;a+i指向一个数组;a、*a和&a[0][0]数值相同;a[i]+j和*(a+i)+j是同一个概念; 总结一下就是:我们对于二维指针a,他指向数组a[0,1,2,3],使用*,可以使他降级到第二层次,这样*a就指向了第一个真正的数组。对于其他的情况我们也可以采用相同的方式,对于其他维数和类型的数组我们可以采用相类似的思想。 int (*p)[5]; 这时p就是一个指针,要指向一个含有5个int类型元素的数组,指向其他的就会出现问题。 C)指针数组 int *p[10];//而不能是int (*p)[10] 或者 char *p[10]; 此时p是一个指针(数值上和&p[0]一样); int * pt=t;//使用pt指向t 那么这里我们用什么指向int *t[10]中的t呢?我们要使用一个指针的指针: int **pt=t; 这是因为:在int *t[10]中,每个元素是指针,那么同时t又指向这个数组,数组上和&t[0]相同,也就是指向t[0],指向一个指针变量,可以说是一个指针的指针了,所以自然要用 int **pt;
int *p1=&i; int**p2=&p1; 综合以上的所有点,下面是我们常常看到一些匹配(也是经常出错的地方): int a[3],b[2][3],c,*d[3]; void fun1(int *p); void fun2(int (*p)[3]); void fun3(int **p); void fun4(int p[3]); void fun5(int p[]); void fun6(int p[2][3]); void fun7(int (&p)[3]); 自己加上的:int (&p)[3]:p是一个引用,引用的是一个一维数组;
#include <string.h>
void fun7(int (&p)[3])
void main() 跟int *p的不同点在于 int t1[4] = {1,2,3,4}; 而 int t1[4] = {1,2,3}; 最新C99标准 int f(int t[3]);参数的数组个数最少为3; 数组没有像malloc一样有信息头;所以是经过在编译时检查的;同时说明sizeof(数组名)是编译时生成;
函数 不会产生编译时刻的可能值(但逻辑上不一定都对)
|
-------------------------------------------------------------------------分页------------------------------------------------------------------------------------------
为什么可以有这样的搭配,原因如下: 对于fun1 fun4 fun 5: 在编译器看来fun1,fun4,fun5的声明是一样,在编译时候,编译器把数组的大小舍去不考虑,只考虑它是一个指针,也就是说有没有大小说明是一样的,所以三者的形式都是fun1的形式(其实只要提供了int*指针就可以了);对于fun7 :以上的解释对于引用是不适用的,如果变量被声明为数组的引用,那么编译器就要考虑数组的大小了,那么必须和声明一模一样(所以fun7就只有a合适);对于fun2:p是一个指向一个含有3个元素的数组,这样b和b+i正好合适,而a却不是(它是指向a[0]的,不是指向这个数组的);对于fun3:p是一个指针的指针,而d指向d[0],同时d[0]又是一个指针,所以d就是一个指针的指针。但是b却不是(它是一个2*3的矩阵也就是年int [2][3]类型);对于fun6,p是一个2*3的数组类型,和b恰好完全匹配;
A) 函数指针 int (*p)(int I,int j); 不能是 int *p(int I,int j), 这样就变成了返回指针的函数声明了。 在C++中处于对安全性的考虑,指针和它指向的对象要类型一致,也就说上面的指针所指向的函数的特性要和它一模一样:例如指向int min(int I,int j);是可以的。但是指向int min(double I ,double j);是不可以。函数指针也和其他的指针一样,在使用的时候很怕发生"悬空",所以在使用的时候同样要判断有效性,或者在定义的时候就初始化。 int (*p)(int I,int j)=min; int (*p)(int I,int j)=&min; int (*p)(int I,int j)=0; B) 函数的指针参数 templateT integrate( T lower, T upper , T (*)(T)=0 )throw(integrated_exp); 这里的最后的参数是一个函数的指针,并且被设定缺省值为0。这个函数返回一个值,同时需要一个参数。假如加入我们有这样的一个函数: double line(double x){ return a*x+b;} 那么我就可以使用了。 typedef int (*PF)(int ); PF getProcessMethod( );//true C) 返回指针的函数 UserType * Process( ) { UserType ut(param-list); //process ut; return &ut;// } 这个变量在我们的函数结束的时候就被销毁了,尽管地址可以传出去,但是这个地址已经不存在了,已经不能使用的东西,在这个函数之外却不知道,难免要出错! UserType * Process ( ) { UserTpye *put=new UserType(param-list ); //process put; return put; } 我们在函数内部使用了一个new,分配了一个空间,这样传出来也是可以! 三、类成员的指针 类成员和一般的外部变量相互比较,不同就是它所在的域不同,这个域很重要,它决定了该变量可以使用的范围。那么一个指针如果要指向类的成员函数或者成员变量,那么除了要表达它的返回类型、参数列表或者类型之外,那么还要说明它所指向的变量(或者函数)的域,为了说明该域我们要使用类域限定: class NJUPT { static double money=20000000; int num; public: NJUPT():num(10){}; int get(){return num;}; double getMoney(){reuturn money;} } 我们定义成员的指针为 int NJUPT:: *p;//指向int型成员变量 int (NJUPt::*)p()//指向int f()型成员函数。 为了使用这些指针,我们需要使用该类型的变量或者指针。 NJUPT s,*ps; 那么调用的方式为: cout<*p)(); 这个看起来似乎很奇怪!但是只要你想到我们定义的指针被限定在了类域中了(我们在开始定义的使用使用了NJUPT:: ),这么使用也是很自然的。 double *p=&NJUPT::money; double (*p)()=&NJUPT::getMoney(): |