转自 http://blog.csdn.net/mbh_1991/article/details/10382771
指针这一节是本书中最难的一节,尤其是二级指针和二维数组直接的关系。
本节知识点:
第二个意义是 数组名 sizeof(a) 为整体数组有多少个字节
- #include <stdio.h>
- #include <stdlib.h>
- int main(int argc, char *argv[])
- {
- /* int a[20]={1,2,4};
- printf("%d\n",sizeof(a));
- printf("%p\n",a);
- printf("%p\n",&a);
- printf("%p\n",&a[0]);
- */
- /* int a[5]={1,2,3,4,5};
- int (*p)[5]=&a;
- printf("%d\n",*((int *)(p+1)-1));
- */
- int a[5]={1,2,3,4,5};
- int* p=(int *)(&a+1);
- // int *p=&a+1; //这个条语句是 把&a这个数组指针 进行了指针运算后 的那个地址 强制类型转换成了 int *指针
- printf("%d\n",*(p-1));
- return 0;
- }
数组是数组,指针是指针,根本就是两个完全不一样的东西。当然要是在宏观的内存角度看,那一段相同类型的连续空间,可以说的上是数组。 但是你可以尝试下,定义一个指针,在其他地方把他声明成数组,看看编译器会不会把两者混为一谈,反过来也不会。
- char a[5]={'a','b','c','d','e'};
- char (*p)[3]=&a;
- #include <stdio.h>
- #include <assert.h>
- int strlen(const char* s)
- {
- return ( assert(s), (*s ? (strlen(s+1) + 1) : 0) );
- }
- int main()
- {
- printf("%d\n", strlen( NULL));
- return 0;
- }
- #include <stdio.h>
- #include <assert.h>
- char* strcpy(char* dst, const char* src)
- {
- char* ret = dst;
- assert(dst && src);
- while( (*dst++ = *src++) != '\0' );
- return ret;
- }
- int main()
- {
- char dst[20];
- printf("%s\n", strcpy(dst, "hello!"));
- return 0;
- }
f.补充问题,为什么对于字符串char a[256] = "hello";,在printf和scanf函数中,使用a行,使用&a也行?代码如下:
- #include <stdio.h>
- int main()
- {
- char* p ="phello";
- char a[256] = "aworld";
- char b[25] = {'b','b','c','d'};
- char (*q)[256]=&a;
- printf("%p\n",a); //0022fe48
- //printf("%p\n",&a);
- //printf("%p\n",&a[0]);
- printf("tian %s\n",(0x22fe48));
- printf("%s\n",q); //q就是&a
- printf("%s\n",*q); //q就是a
- printf("%s\n",p);
- printf("%s\n",a);
- printf("%s\n",&a);
- printf("%s\n",&a[0]);
- printf("%s\n",b);
- printf("%s\n",&b);
- printf("%s\n",&b[0]);
- }
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- int main(int argc, char *argv[])
- {
- int a[3][3]={1,2,3,4,5,6,7,8,9};
- printf("%d\n",sizeof(a[0]));
- printf("%d\n",*a[2]);
- printf("%d\n",*(a[0]+1));
- printf("%p\n",a[0]);
- printf("%p\n",a[1]);
- printf("%p\n",&a[0]+1); //&a[0]+1 跟 a[1]不一样 指针类型不一样 &a[0]+1这个是数组指针 a[1]是&a[1][0] 是int*指针
- printf("%d\n",*((int *)(&a[0]+1)));
- printf("%d\n",*(a[1]+1));
- printf("%p\n",a);
- printf("%p\n",&a);
- printf("%p\n",&a[0]);
- printf("%d\n",sizeof(a)); //这是a当作数组名的时候
- printf("%d\n",*((int *)(a+1))); //此时 a是数组首元素的地址 数组首元素是a[0]
- //首元素地址是&a[0] 恰巧a[0]是数组名 &a[0]就变成了数组指针
- return 0;
- }
- int *q;
- q = (int *)a;
- printf("%d\n",*(q+6));
- int (*p)[3];
- p = a;
- printf("%d\n",*(*(p+1)+1));
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int main()
- {
- int a[3][3]={1,2,3,4,5,6,7,8,9};
- int (*p)[3];
- int *q;
- printf("%d\n",*(*(a+1)+1)); //a *(&a[0]+1)
- p = a;
- q = (int *)a;
- printf("%d\n",*(*(p+1)+1));
- printf("%d\n",*(a[1]+1));
- printf("%d\n",a[1][1]);
- printf("%d\n",*(q+6));
- }
- <span style="font-family:Arial;BACKGROUND-COLOR: #ffffff"></span>
- <span style="color:#000000;">#include <stdio.h>
- int main()
- {
- int a[5][5];
- int(*p)[4];
- p = a;
- printf("%d\n", &p[4][2] - &a[4][2]);
- }</span>
- #include <stdio.h>
- #include <malloc.h>
- int reset(char**p, int size, int new_size)
- {
- int ret = 1;
- int i = 0;
- int len = 0;
- char* pt = NULL;
- char* tmp = NULL;
- char* pp = *p;
- if( (p != NULL) && (new_size > 0) )
- {
- pt = (char*)malloc(new_size);
- tmp = pt;
- len = (size < new_size) ? size : new_size;
- for(i=0; i<len; i++)
- {
- *tmp++ = *pp++;
- }
- free(*p);
- *p = pt;
- }
- else
- {
- ret = 0;
- }
- return ret;
- }
- int main()
- {
- char* p = (char*)malloc(5);
- printf("%0X\n", p);
- if( reset(&p, 5, 3) )
- {
- printf("%0X\n", p);
- }
- return 0;
- }
(2)函数中传递指针数组的时候,实参(指针数组)要退化成形参(二级指针)。
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- int main(int argc, char *argv[])
- {
- char* p[4]={"afje","bab","ewrw"};
- char* *d=p;
- printf("%s\n",*(p+1));
- printf("%s\n",*(d+1)); //d &p[0] p[0]是"afje"的地址,所以&p[0]是保存"afje"字符串的char*指针的地址
- return 0;
- }
d.子函数malloc,主函数free,这是可以的(有两种办法,第一种是利用return 把malloc的地址返回。第二种是利用二级指针,传递一个指针的地址,然后把malloc的地址保存出来)。记住不管函数参数是,指针还是数组, 当改变了指针的指向的时候,就会出问题,因为子函数中的指针就跟主函数的指针不一样了,他只是一个复制品,但可以改变指针指向的内容。这个知识点可以看<在某培训机构的听课笔记>这篇文章。
13.数组作为函数参数:数组作为函数的实参的时候,往往会退化成数组元素类型的指针。如:int a[5],会退化成int* ;指针数组会退化成二级指针;二维数组会退化成一维数组指针;三维数组会退化成二维数组指针(三维数组的这个是我猜得,如果说错了,希望大家帮我指出来,谢谢)。如图:
二维数组作为实参的例子:
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- int fun(int (*b)[3]) //此时的b为 &a[0]
- {
- printf("%d\n",*(*(b+1)+0));
- printf("%d\n",b[2][2]);// b[2][2] 就是 (*(*(b+2)+2))
- printf("%d\n",*(b[1]+2));
- }
- int main(int argc, char *argv[])
- {
- int a[3][3]={1,2,3,4,5,6,7,8,9};
- fun(a);//与下句话等价
- fun(&a[0]);
- return 0;
- }
数组当作实参的时候,会退化成指针。指针当做实参的时候,就是单纯的拷贝了!
14.函数指针与指针函数:
a.对于函数名来说,它是函数的入口,其实函数的入口就是一个地址,这个函数名也就是这个地址。这一点用汇编语言的思想很容易理解。下面一段代码说明函数名其实就是一个地址,代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- void abc()
- {
- printf("hello fun\n");
- }
- int main(int argc, char *argv[])
- {
- void (*d)();
- void (*p)();
- p = abc;
- abc();
- printf("%p\n",abc);
- printf("%p\n",&abc);//函数abc的地址0x40138c
- p();
- (*p)();
- d = ((unsigned int*)0x40138c); //其实就算d= 0x40138c这么给赋值也没问题
- d();
- return 0;
- }
可见函数名就是一个地址,所以函数名abc与&abc没有区别,所以p和*p也没有区别。
b.我觉得函数指针最重要的是它的应用环境,如回调函数(其实就是利用函数指针,把函数当作参数进行传递)代码如下,还有中断处理函数(同理)详细见<
ok6410学习笔记(16.按键中断控制led)>中的 中断注册函数,request_irq。还有就是函数指针数组,第一次见到函数指针数组是在zigbee协议栈中。
回调函数原理代码:
- #include <stdio.h>
- typedef int(*FUNCTION)(int);
- int g(int n, FUNCTION f)
- {
- int i = 0;
- int ret = 0;
- for(i=1; i<=n; i++)
- {
- ret += i*f(i);
- }
- return ret;
- }
- int f1(int x)
- {
- return x + 1;
- }
- int f2(int x)
- {
- return 2*x - 1;
- }
- int f3(int x)
- {
- return -x;
- }
- int main()
- {
- printf("x * f1(x): %d\n", g(3, f1));
- printf("x * f2(x): %d\n", g(3, &f2));
- printf("x * f3(x): %d\n", g(3, f3));
- }
注意:可以使用函数名f2,函数名取地址&f2都可以,但是不能有括号。
c.所谓指针函数其实真的没什么好说的,就是一个返回值为指针的函数而已。
15.赋值指针的阅读:
a.char* (*p[3])(char* d); 这是定义一个函数指针数组,一个数组,数组元素都是指针,这个指针是指向函数的,什么样的函数参数为char* 返回值为char*的函数。
分析过程:char (*p)[3] 这是一个数组指针、char* p[3] 这是一个指针数组 char* 是数组元素类型、char* p(char* d) 这个是一个函数返回值类型是char* 、char (*p)(char* d)这个是一个 函数指针。可见char* (*p[3])(char* d)是一个数组 数组中元素类型是 指向函数的指针,char* (* )(char* d) 这是函数指针类型,char* (* )(char* d) p[3] 函数指针数组 这个不好看 就放里面了。(PS:这个看看就好了~~~当娱乐吧)
b.函数指针数组的指针:char* (*(*pf)[3])(char* p) //这个就看看吧 我觉得意义也不大 因为这个逻辑要是一直下去 就递归循环了。
分析过程:char* (* )(char *p) 函数指针类型,char* (*)(char *p) (*p)[3] 函数指针 数组指针 也不好看 就放里面了。