翻译建设企业网站,wordpress的首页文件夹,建设网站都需要注意什么,恩施网站定制具体关于c指针说明可参考前面两篇文章。C中指针详解和C中复杂类型声明。 1、二维数组 下面就三种二维数组进行说明。 1: int **Ptr; 2: int *Ptr[ 5 ]; 3: int ( *Ptr )[ 5 ]; 以上三例都是整数的二维数组#xff0c;都可以用形如 Ptr[ 1 ][ 1 ] 的方式访问其内容#xff1b;… 具体关于c指针说明可参考前面两篇文章。C中指针详解和C中复杂类型声明。 1、二维数组 下面就三种二维数组进行说明。 1: int **Ptr; 2: int *Ptr[ 5 ]; 3: int ( *Ptr )[ 5 ]; 以上三例都是整数的二维数组都可以用形如 Ptr[ 1 ][ 1 ] 的方式访问其内容但它们的差别却是很大的。下面我从四个方面对它们进行讨论 1.1、内容 它们本身都是指针它们的最终内容都是整数。注意我这里说的是最终内容而不是中间内容比如你写 Ptr[ 0 ]对于三者来说其内容都是一个整数指针即 int *Ptr[ 1 ][ 1 ] 这样的形式才是其最终内容。 1.2、意义 1: int **Ptr 表示指向一群指向整数的指针的指针。 2: int *Ptr[ 5 ] 表示指向 5 个指向整数的指针的指针。 3: int ( *Ptr )[ 5 ] 表示指向一群指向 5 个整数数组的指针的指针。 1.3、所占空间 (1)、int **Ptr 和 (3)、int ( *Ptr )[ 5 ] 一样在32位平台里都是4字节即一个指针。 (2)、int *Ptr[ 5 ] 不同它是 5 个指针它占5 * 4 20个字节的内存空间。 1.4、用法 (1)、int **Ptr 因为是指针的指针需要两次内存分配才能使用其最终内容。首先Ptr ( int ** )new int *[ 5 ]这样分配好了以后它和(2)的意义相同了然后要分别对 5 个指针进行内存分配例如 Ptr[ 0 ] new int[ 20 ]; 它表示为第 0 个指针分配 20 个整数分配好以后 Ptr[ 0 ] 为指向 20 个整数的数组。这时可以使用下标用法 Ptr[ 0 ][ 0 ] 到Ptr[ 0 ][ 19 ] 了。 如果没有第一次内存分配该 Ptr 是个野指针是不能使用的如果没有第二次内存分配则 Ptr[ 0 ] 等也是个野指针也是不能用的。当然用它指向某个已经定义的地址则是允许的那是另外的用法类似于借鸡生蛋的做法这里不作讨论下同。 (2)、int *Ptr[ 5 ] 这样定义的话编译器已经为它分配了 5 个指针的空间这相当于(1)中的第一次内存分配。根据对(1)的讨论可知显然要对其进行一次内存分配的。否则就是野指针。 (3)、int ( *Ptr )[ 5 ] 这种定义我觉得很费解不是不懂而是觉得理解起来特别吃力也许是我不太习惯这样的定义吧。怎么描述它呢它的意义是一群指针每个指针都是指向一个 5 个整数的数组。如果想分配 k 个指针这样写 Ptr ( int ( * )[ 5 ] ) new int[ sizeof( int ) * 5 * k ]。这是一次性的内存分配。分配好以后Ptr 指向一片连续的地址空间 其中 Ptr[ 0 ] 指向第 0 个 5 个整数数组的首地址Ptr[ 1 ] 指向第1 个 5 个整数数组的首地址。 综上所述我觉得可以这样理解它们 int ** Ptr int Ptr[ x ][ y ]; int *Ptr[ 5 ] int Ptr[ 5 ][ x ]; int ( *Ptr )[ 5 ] int Ptr[ x ][ 5 ]; 这里 x 和 y 是表示若干的意思。 2、函数指针和指针函数 2.1、通常的函数调用 一个通常的函数调用的例子 1: void MyFun(int x); //此处的申明也可写成void MyFun( int ); 2: int main(int argc, char* argv[]) 3: { 4: MyFun(10); //这里是调用MyFun(10);函数 5: return 0; 6: } 7: void MyFun(int x) //这里定义一个MyFun函数 8: { 9: printf(“%d\n”,x); 10: } 这个MyFun函数是一个无返回值的函数它并不完成什么事情。这种调用函数的格式你应该是很熟悉的吧看主函数中调用MyFun函数的书写格式 MyFun(10); 我们一开始只是从功能上或者说从数学意义上理解MyFun这个函数知道MyFun函数名代表的是一个功能或是说一段代码。 直到学习到函数指针概念时。我才不得不在思考函数名到底又是什么东西呢 【js中函数】不要以为这是没有什么意义的事噢呵呵继续往下看你就知道了。 2.2、函数指针变量的申明 就象某一数据变量的内存地址可以存储在相应的指针变量中一样函数的首地址也以存储在某个函数指针变量里的。这样我就可以通过这个函数指针变量来调用所指向的函数了。 在C系列语言中任何一个变量总是要先申明之后才能使用的。那么函数指针变量也应该要先申明吧那又是如何来申明呢以上面的例子为例我来申明一个可以指向MyFun函数的函数指针变量FunP。下面就是申明FunP变量的方法 void (*FunP)(int) ; //也可写成void (*FunP)(int x); 你看整个函数指针变量的申明格式如同函数MyFun的申明处一样只不过——我们把MyFun改成*FunP而已这样就有了一个能指向MyFun函数的指针FunP了。当然这个FunP指针变量也可以指向所有其它具有相同参数及返回值的函数了。 2.3、通过函数指针变量调用函数 有了FunP指针变量后我们就可以对它赋值指向MyFun然后通过FunP来调用MyFun函数了。看我如何通过FunP指针变量来调用MyFun函数的 具体可参考C 虚函数表解析 1: void MyFun(int x); //这个申明也可写成void MyFun( int ); 2: void (*FunP)(int ); //也可申明成void(*FunP)(int x)但习惯上一般不这样。 3: int main(int argc, char* argv[]) 4: { 5: MyFun(10); //这是直接调用MyFun函数 6: //将MyFun函数的地址赋给FunP变量 7: //这是通过函数指针变量FunP来调用MyFun函数的。 8: } 9: void MyFun(int x) //这里定义一个MyFun函数 10: { 11: printf(“%d\n”,x); 12: } 运行看看。嗯不错程序运行得很好。 哦我的感觉是MyFun与FunP的类型关系类似于int 与int *的关系。函数MyFun好像是一个如int的变量或常量而FunP则像一个如int *一样的指针变量。 int i,*pi; pii; //与FunPMyFun比较。你的感觉呢 呵呵其实不然—— 。。。。。 2.4、调用函数的其它书写格式 函数指针也可如下使用来完成同样的事情 1: void MyFun(int x); 2: void (*FunP)(int ); //申明一个用以指向同样参数返回值函数的指针变量。 3: int main(int argc, char* argv[]) 4: { 5: MyFun(10); //这里是调用MyFun(10);函数 6: //将MyFun函数的地址赋给FunP变量 7: //这是通过函数指针变量来调用MyFun函数的。 8: return 0; 9: } 10: void MyFun(int x) //这里定义一个MyFun函数 11: { 12: printf(“%d\n”,x); 13: } 运行试试啊一样地成功。 咦 FunPMyFun; 可以这样将MyFun值同赋值给FunP难道MyFun与FunP是同一数据类型即如同的int 与int的关系而不是如同int 与int*的关系了有没有一点点的糊涂了 看来与之前的代码有点矛盾了是吧所以我说嘛 请容许我暂不给你解释继续看以下几种情况这些可都是可以正确运行的代码哟 代码之三 1: int main(int argc, char* argv[]) 2: { 3: MyFun(10); //这里是调用MyFun(10);函数 4: //将MyFun函数的地址赋给FunP变量 5: //这是通过函数指针变量来调用MyFun函数的。 6: return 0; 7: } 代码之四 1: int main(int argc, char* argv[]) 2: { 3: MyFun(10); //这里是调用MyFun(10);函数 4: //将MyFun函数的地址赋给FunP变量 5: //这是通过函数指针变量来调用MyFun函数的。 6: return 0; 7: } 真的是可以这样的噢 1: int main(int argc, char* argv[]) 2: { 3: *MyFun(10); //看函数名MyFun也可以有这样的调用格式 4: return 0; 5: } 你也许第一次见到吧函数名调用也可以是这样写的啊只不过我们平常没有这样书写罢了。 那么这些又说明了什么呢 呵呵依据以往的知识和经验来推理本篇的“新发现”我想就连“福尔摩斯”也必定会由此分析并推断出以下的结论 1. 其实MyFun的函数名与FunP函数指针都是一样的即都是函数指针。MyFun函数名是一个函数指针常量而FunP是一个函数数指针变量这是它们的关系。 2. 但函数名调用如果都得如(*MyFun)(10)这样那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许MyFun(10);这种形式地调用这样方便多了并与数学中的函数形式一样不是吗。 3. 为统一起见FunP函数指针变量也可以FunP(10)的形式来调用。 4. 赋值时即可FunPMyFun形式也可FunPMyFun。 上述代码的写法随便你爱怎么着 请这样理解吧这可是有助于你对函数指针的应用喽 最后补充说明一点在函数的申明处 void MyFun(int ); //不能写成void (*MyFun)(int )。 void (*FunP)(int ); //不能写成void FunP(int )。 请看注释这一点是要注意的。 2.5、定义某一函数的指针类型 就像自定义数据类型一样我们也可以先定义一个函数指针类型然后再用这个类型来申明函数指针变量。 我先给你一个自定义数据类型的例子。 1: typedef int* PINT; //为int* 类型定义了一个PINT的别名 2: int main() 3: { 4: int x; 5: PINT pxx; //与int * pxx;是等价的。PINT类型其实就是int * 类型 6: *px10; //px就是int*类型的变量 7: return 0; 8: } 根据注释应该不难看懂吧虽然你可能很少这样定义使用但以后学习Win32编程时会经常见到的。 下面我们来看一下函数指针类型的定义及使用请与上对照 1: void MyFun(int x); //此处的申明也可写成void MyFun( int ); 2: typedef void (*FunType)(int ); //这样只是定义一个函数指针类型 3: FunType FunP; //然后用FunType类型来申明全局FunP变量 4: int main(int argc, char* argv[]) 5: { 6: //FunType FunP; //函数指针变量当然也是可以是局部的 那就请在这里申明了。 7: MyFun(10); 8: FunPMyFun; 9: (*FunP)(20); 10: return 0; 11: } 12: void MyFun(int x) 13: { 14: printf(“%d\n”,x); 15: } 首先在void (*FunType)(int ); 前加了一个typedef 。这样只是定义一个名为FunType函数指针类型而不是一个FunType变量。 然后FunType FunP; 这句就如PINT px;一样地申明一个FunP变量。 其它相同。整个程序完成了相同的事。 这样做法的好处是 有了FunType类型后我们就可以同样地、很方便地用FunType类型来申明多个同类型的函数指针变量了。如下 FunType FunP2; FunType FunP3; //…… 2.6、函数指针作为某个函数的参数 既然函数指针变量是一个变量当然也可以作为某个函数的参数来使用的。所以你还应知道函数指针是如何作为某个函数的参数来传递使用的。 给你一个实例要求我要设计一个CallMyFun函数这个函数可以通过参数中的函数指针值不同来分别调用MyFun1、MyFun2、MyFun3这三个函数注这三个函数的定义格式应相同。 【类似C#中delegate】实现代码如下 1: void MyFun1(int x); 2: void MyFun2(int x); 3: void MyFun3(int x); 4: typedef void (*FunType)(int ); //②. 定义一个函数指针类型FunType,与①函数类型一至 5: void CallMyFun(FunType fp,int x); 6: int main(int argc, char* argv[]) 7: { 8: CallMyFun(MyFun1,10); //⑤. 通过CallMyFun函数分别调用三个不同的函数 9: CallMyFun(MyFun2,20); 10: CallMyFun(MyFun3,30); 11: } 12: void CallMyFun(FunType fp,int x) //③. 参数fp的类型是FunType。 13: { 14: fp(x);//④. 通过fp的指针执行传递进来的函数注意fp所指的函数是有一个参数的 15: } 16: void MyFun1(int x) // ①. 这是个有一个参数的函数以下两个函数也相同 17: { 18: printf(“函数MyFun1中输出%d\n”,x); 19: } 20: void MyFun2(int x) 21: { 22: printf(“函数MyFun2中输出%d\n”,x); 23: } 24: void MyFun3(int x) 25: { 26: printf(“函数MyFun3中输出%d\n”,x); 27: } 输出结果略 分析看我写的注释。你可按我注释的①②③④⑤顺序自行分析。 指针函数 一个函数不仅可以带回一个整型数据的值字符类型值和实型类型的值还可以带回指针类型的数据使其指向某个地址单元。 返回指针的函数一般定义格式为 类型标识符 *函数名(参数表) int *f(xy); 其中xy是形式参数f是函数名调用后返回一个指向整型数据的地址指针。f(xy)是函数其值是指针。 如char *ch();表示的就是一个返回字符型指针的函数请看下面的例题 在C中函数返回值默认为int 【例】将字符串1(str1)复制到字符串2(str2)并输出字符串2。 1: #include stdio.h 2: 3: main() 4: 5: { 6: 7: char *ch(char *char *); 8: 9: char str1[]I am glad to meet you!; 10: 11: char str2[]Welcom to study C!; 12: 13: printf(%sch(str1str2)); 14: 15: } 16: 17: char *ch(char *str1char *str2) 18: 19: { 20: 21: int i; 22: 23: char *p; 24: 25: pstr2 26: if(*str2NULL) exit(-1); 27: 28: do 29: 30: { 31: 32: *str2*str1; 33: 34: str1; 35: 36: str2; 37: 38: }while(*str1!NULL); 39: 40: return(p); 41: 42: } 通过分析可得 函数指针是一个指向函数的指针而指针函数只是说明他是一个返回值为指针的函数函数指针可以用来指向一个函数。 3、数组指针和指针数组 3.1、数组指针也称行指针 定义 int (*p)[n];()优先级高首先说明p是一个指针指向一个整型的一维数组这个一维数组的长度是n也可以说是p的步长。也就是说执行p1时p要跨过n个整型数据的长度。 如要将二维数组赋给一指针应这样赋值 1: int a[3][4]; 2: int (*p)[4]; //该语句是定义一个数组指针指向含4个元素的一维数组。 3: pa; //将该二维数组的首地址赋给p也就是a[0]或a[0][0] 4: p; //该语句执行过后也就是pp1;p跨过行a[0][]指向了行a[1][] 所以数组指针也称指向一维数组的指针亦称行指针。 3.2、指针数组 定义 int *p[n];[]优先级高先与p结合成为一个数组再由int*说明这是一个整型指针数组它有n个指针类型的数组元素。这里执行p1是错误的这样赋值也是错误的pa因为p是个不可知的表示只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *pa; 这里*p表示指针数组第一个元素的值a的首地址的值。如要将二维数组赋给一指针数组: 1: int *p[3]; 2: int a[3][4]; 3: for(i0;i3;i) 4: p[i]a[i];这里int *p[3] 表示一个一维数组内存放着三个指针变量分别是p[0]、p[1]、p[2]。所以要分别赋值。 这样两者的区别就豁然开朗了数组指针只是一个指针变量似乎是C语言里专门用来指向二维数组的它占有内存中一个指针的存储空间。指针数组是多个指针变量以数组形式存在内存当中占有多个指针的存储空间。还需要说明的一点就是同时用来指向二维数组时其引用和用数组名引用都是一样的。比如要表示数组中i行j列一个元素*(p[i]j)、*(*(pi)j)、(*(pi))[j]、p[i][j] 参考资料 1、二维数组指针 2、函数指针 3、数组指针转载于:https://www.cnblogs.com/ttltry-air/archive/2012/08/28/2659829.html