数组-函数-指针
1. 注释方法
2. 空指针与野指针 1 2 3 4 5 6 int *p = NULL ; 如何杜绝: 定义指针开始就应该初始化,或者使其指向NULL 如:int *p = 123 ;
3. 空类型指针
4. 指针与数组 (1)指针与一维数组 可以使用一级指针指向一维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <stdlib.h> int main () { int a[3 ] = {1 ,2 ,3 }; int i; for (i = 0 ;i<sizeof (a)/sizeof (a[0 ]);i++) printf ("%p-->%d\n" ,&a[i],a[i]); printf ("\n" ); int *p = a; printf ("第一个元素地址: %p--> 第一个元素为: %d\n" ,p,*p); for (i = 0 ;i<sizeof (a)/sizeof (a[0 ]);i++) printf ("%p-->%d\n" ,(p+i),*(p+i)); exit (0 ); }
(2)指针与二维数组 Warning:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> #include <stdlib.h> int main () { int a[2 ][2 ] = {1 ,2 ,3 ,4 }; int *p = a; printf ("%p %p\n" ,a,a+1 ); int i,j; for (i = 0 ;i < 2 ; i++) { for (j = 0 ;j < 2 ; j++) { printf ("%p --> %d\n" ,&a[i][j],a[i][j]); } } exit (0 ); }
编译之后会出现以下Warning:
运行之后发现:
数组名a是:a[0] [0]的地址 a,a+1是:a[1] [0]的地址,a+1 是在行间进行跳跃,而p指向的是二维数组首地址,p+1指向的是a[0] [1],p是在列之间进行跳跃
1 2 3 int *p = a;int *p = *(a+0 );
对于二维数组也可以如此遍历:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <stdlib.h> int main () { int a[2 ][2 ] = {1 ,2 ,3 ,4 }; int *p = *a; printf ("%p %p\n" ,a,a+1 ); int i,j; for (i = 0 ;i < 2 ; i++) { for (j = 0 ;j < 2 ; j++) { printf ("%p --> %d\n" ,*(a+i)+j,*(*(a+i)+j)); } } exit (0 ); }
通过列指针p进行遍历二维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> #include <stdlib.h> int main () { int a[2 ][2 ] = {1 ,2 ,3 ,4 }; int *p = *a; printf ("%p %p\n" ,a,a+1 ); int i; for (i = 0 ; i<4 ;i++) { printf ("%p --> %d\n" ,p+i,*(p+i)); } exit (0 ); }
数组指针(重点) 指向数组的指针
1 数据类型 (*指针名)[] = 二维数组首地址;
例如:
1 2 3 4 5 int a[2 ][3 ] = {{1 ,2 ,3 },{4 ,5 ,6 }};int (*p)[3 ] = a;
例程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> #include <stdlib.h> int main () { int a[2 ][3 ] = {{1 ,2 ,3 },{4 ,5 ,6 }}; int (*p)[3 ]; p = a; printf ("%p---->%d--->%p---->%d\n" ,p,(*p)[0 ],p+1 ,*(p+1 )[0 ]); printf ("%p---->%d---->%p--->%d\n" ,a,(*a)[0 ],a+1 ,*(a+1 )[0 ]); int i,j; for (i=0 ;i<2 ;i++) { for (j=0 ;j<3 ;j++) { printf ("%p --> %d\n" ,*(p+i)+j,*(*(p+i)+j)); } } return 0 ; }
运行结果
5.指针数组 定义一个数组,里面的元素为指针
1 2 3 4 5 数据类型 *数组名 [长度]; int a = 1 ,b = 2 , c = 3 ;int *p[3 ] = {&a,&b,&c};
例程:
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> #include <stdlib.h> #include <string.h> int main () { int a = 1 ,b = 2 , c = 3 ; int *p[3 ] = {&a,&b,&c}; printf ("%p---%p---%p\n" ,&a,&b,&c); printf ("%d---%d---%d\n" ,*p[0 ],*p[1 ],*p[2 ]); exit (0 ); }
6.指针函数与函数指针 (1)指针函数 指针函数本质还是一个函数,返回为一个指针,地址
func
是一个函数,args
是形参列表,ret *
作为一个整体,是 func
函数的返回值,是一个指针的形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> int *sum (int a, int b) { static int result; int *p; result = a + b; p = &result; return p; } int main () { int a = 10 ; int b = 10 ; int *p = sum(a, b); printf ("the result is %d" ,*p); }
示例二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> int *sum (int a, int b) { int result; int *p; result = a + b; p = &result; return p; } int main () { int a = 10 ; int b = 10 ; int *p = sum(a, b); printf ("the result is %d" ,*p); }
上述两个实例,结果输出,并无差别,但是如果我们在main函数中做一些修改如下:
示例三:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> int *sum (int a, int b) { int result; int *p; result = a + b; p = &result; return p; } int main () { int a = 10 ; int b = 10 ; int *p = sum(a, b); printf ("wait for a while...\n" ); printf ("the result is %d" ,*p); }
运行结果
出现以上结果的原因:
一般的局部变量存在在栈区 ,当函数结束,栈区变量就会释放,倘若在函数内部定义一个局部变量,在使用指针指向该变量,当函数调用结束,这个变量的空间就会被释放。这是放回该地址的指针,也不一定得到正确的结果,上述示例一、示例二 ,在返回指针后,立马访问也是巧合。但是如果我们等待一段时间再去访问,这是可能该地址,可能地址以及被其他变量所占用
解决方法:
在函数内,使用static去修饰需要返回地址的变量,该变量就会变成静态变量,静态变量存放在数据段。静态变量的生命周期为整个程序的运行周期
使用全局变量,全局变量同样存放在数据段,其生命周期为整个程序的运行周期 ,但是不推荐!
(2)函数指针 函数指针本质还是指针,指向函数的指针
1 2 3 4 ret (*p)(args, ...); typedef int (*fun_ptr) (int ,int ) ;
函数指针初始化:
实例程序
以下实例声明了函数指针变量 p,指向函数 max:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> int max(int x, int y) { return x > y ? x : y; } int main(void) { /* p 是函数指针 */ int (* p)(int, int) = & max; // &可以省略 int a, b, c, d; printf("请输入三个数字:"); scanf("%d %d %d", & a, & b, & c); /* 与直接调用函数等价,d = max(max(a, b), c) */ d = p(p(a, b), c); printf("最大的数字是: %d\n", d); return 0; }
以下实例声明了函数指针变量p,指向函数sum
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int sum (int a,int b) { return a + b; } int main () { int (*p)(int a, int b); p = ∑ int a = 1 ; int b = 2 ; int c = 3 ; int result = p(p(a,b),c); printf ("the result is %d" ,result); }
(3)函数指针数组 定义
1 2 3 类型 (*数组名[下标]) (形参) 如: int (*arr[N])(int ) 如何理解:先看括号,首先是一个数组其次是一个指针 括号中整体就是 指针数组;最后还是一个函数;三者组合就是 函数指针数组
(4)回调函数 回调函数通过函数指针 调用
的函数。其将函数指针作为一个参数,传递给另一个函数。回调函数并不是由实现方直接调用,而是在特定的事件或条件发生时由另外一方来调用的。
函数指针的一个非常典型的应用就是回调函数
回调函数是由别人的函数执行时调用你实现的函数。
实例程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <stdio.h> #include <stdlib.h> int func_sum (int n) { int sum = 0 ; if (n < 0 ) { printf ("n must be > 0\n" ); exit (-1 ); for (int i = 0 ; i <= n; i++) { sum += i; } return sum; } int callback (int n,int (*p)(int )) { return p(n); } int main () { int n = 5 ; printf ("thr sum is from 0 to %d is %d\n" ,n,callback(n,func_sum)); exit (0 ); }
使用回调函数的优势:
在这个程序中,回调函数callback无需关心func_sum
是怎么实现的,只需要去调用即可。 这样的好处就是,如果以后对求和函数有优化,比如新写了个func_sum2
函数的实现,我们只需要在调用回调函数的地方将函数指针指向func_sum2
即可,而无需去修改callback函数内部。
回调函数广泛用于开发场景中,比如信号函数、线程函数等,都使用到了回调函数的知识。