4.3 一级指针传参
1. #include <stdio.h> 2. void print(int *p, int sz) 3. { 4. int i = 0; 5. for(i=0; i<sz; i++) 6. { 7. printf("%d\n", *(p+i)); 8. } 9. } 10. int main() 11. { 12. int arr[10] = {1,2,3,4,5,6,7,8,9}; 13. int *p = arr; 14. int sz = sizeof(arr)/sizeof(arr[0]); 15. //一级指针p,传给函数 16. print(p, sz); 17. return 0; 18. }
思考:
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
比如:
1. void test1(int *p) 2. {} 3. //test1函数能接收什么参数? 4. void test2(char* p) 5. {} 6. //test2函数能接收什么参数?
4.4 二级指针传参
1. #include <stdio.h> 2. void test(int** ptr) 3. { 4. printf("num = %d\n", **ptr); 5. } 6. int main() 7. { 8. int n = 10; 9. int*p = &n; 10. int **pp = &p; 11. test(pp); 12. test(&p); 13. return 0; 14. }
思考:
当函数的参数为二级指针的时候,可以接收什么参数?
1. void test(char** p) 2. { } 3. int main() 4. { 5. char c = 'b'; 6. char* pc = &c; 7. char** ppc = &pc; 8. char* arr[10]; 9. test(&pc); 10. test(ppc); 11. test(arr);//Ok 12. return 0; 13. }
5. 函数指针
首先看一段代码:
1. #include <stdio.h> 2. void test() 3. { 4. printf("hehe\n"); 5. } 6. int main() 7. { 8. printf("%p\n", test); 9. printf("%p\n", &test); 10. return 0; 11. }
输出的是两个地址,这两个地址是 test 函数的地址。
那我们的函数的地址要想保存起来,怎么保存?
下面我们看代码:
1. //下面pfun1和pfun2哪个有能力存放test函数的地址? 2. void (*pfun1)();//ok 3. void* pfun2();
首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针?
答案是:
pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参
数,返回值类型为void。
6. 函数指针数组
数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,
比如:
1. int *arr[10]; 2. //数组的每个元素是int*
那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
1. int (*parr1[10])(); 2. int *parr2[10](); 3. int (*)() parr3[10];
答案是:parr1
parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。
函数指针数组的用途:转移表
例子:(计算器)
1. #include <stdio.h> 2. 3. int add(int a, int b) 4. { 5. return a + b; 6. } 7. int sub(int a, int b) 8. { 9. return a - b; 10. } 11. int mul(int a, int b) 12. { 13. return a * b; 14. } 15. int div(int a, int b) 16. { 17. return a / b; 18. } 19. int main() 20. { 21. int x, y; 22. int input = 1; 23. int ret = 0; 24. do 25. { 26. printf("*************************\n"); 27. printf(" 1:add 2:sub \n"); 28. printf(" 3:mul 4:div \n"); 29. printf("*************************\n"); 30. printf("请选择:"); 31. scanf("%d", &input); 32. switch (input) 33. { 34. case 1: 35. printf("输入操作数:"); 36. scanf("%d %d", &x, &y); 37. ret = add(x, y); 38. printf("ret = %d\n", ret); 39. break; 40. case 2: 41. printf("输入操作数:"); 42. scanf("%d %d", &x, &y); 43. ret = sub(x, y); 44. printf("ret = %d\n", ret); 45. break; 46. case 3: 47. printf("输入操作数:"); 48. scanf("%d %d", &x, &y); 49. ret = mul(x, y); 50. printf("ret = %d\n", ret); 51. break; 52. case 4: 53. printf("输入操作数:"); 54. scanf("%d %d", &x, &y); 55. ret = div(x, y); 56. printf("ret = %d\n", ret); 57. break; 58. case 0: 59. printf("退出程序\n"); 60. break; 61. default: 62. printf("选择错误\n"); 63. break; 64. } 65. } while (input); 66. return 0; 67. }
使用函数指针数组的实现:
1. #include <stdio.h> 2. int add(int a, int b) 3. { 4. return a + b; 5. } 6. int sub(int a, int b) 7. { 8. return a - b; 9. } 10. int mul(int a, int b) 11. { 12. return a * b; 13. } 14. int div(int a, int b) 15. { 16. return a / b; 17. } 18. int main() 19. { 20. int x, y; 21. int input = 1; 22. int ret = 0; 23. int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表 24. while (input) 25. { 26. printf("*************************\n"); 27. printf(" 1:add 2:sub \n"); 28. printf(" 3:mul 4:div \n"); 29. printf("*************************\n"); 30. printf("请选择:"); 31. scanf("%d", &input); 32. if ((input <= 4 && input >= 1)) 33. { 34. printf("输入操作数:"); 35. scanf("%d %d", &x, &y); 36. ret = (*p[input])(x, y); 37. } 38. else 39. printf("输入有误\n"); 40. printf("ret = %d\n", ret); 41. } 42. return 0; 43. }
7. 指向函数指针数组的指针
指向函数指针数组的指针是一个 指针
指针指向一个 数组 ,数组的元素都是 函数指针 ;
如何定义?
1. void test(const char* str) 2. { 3. printf("%s\n", str); 4. } 5. int main() 6. { 7. //函数指针pfun 8. void (*pfun)(const char*) = test; 9. //函数指针的数组pfunArr 10. void (*pfunArr[5])(const char* str); 11. pfunArr[0] = test; 12. //指向函数指针数组pfunArr的指针ppfunArr 13. void (*(*ppfunArr)[5])(const char*) = &pfunArr; 14. return 0; 15. }
8. 回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
首先演示一下qsort函数的使用:
1. #include <stdio.h> 2. //qosrt函数的使用者得实现一个比较函数 3. int int_cmp(const void * p1, const void * p2) 4. { 5. return (*( int *)p1 - *(int *) p2); 6. } 7. int main() 8. { 9. int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; 10. int i = 0; 11. qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp); 12. for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++) 13. { 14. printf( "%d ", arr[i]); 15. } 16. printf("\n"); 17. return 0; 18. }
使用回调函数,模拟实现qsort(采用冒泡的方式)
1. #include <stdio.h> 2. int int_cmp(const void* p1, const void* p2) 3. { 4. return (*(int*)p1 - *(int*)p2); 5. } 6. void _swap(void* p1, void* p2, int size) 7. { 8. int i = 0; 9. for (i = 0; i < size; i++) 10. { 11. char tmp = *((char*)p1 + i); 12. *((char*)p1 + i) = *((char*)p2 + i); 13. *((char*)p2 + i) = tmp; 14. } 15. } 16. void bubble(void* base, int count, int size, int(*cmp)(void*, void*)) 17. { 18. int i = 0; 19. int j = 0; 20. for (i = 0; i < count - 1; i++) 21. { 22. for (j = 0; j < count - i - 1; j++) 23. { 24. if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0) 25. { 26. _swap((char*)base + j * size, (char*)base + (j + 1) * size, size); 27. } 28. } 29. } 30. } 31. int main() 32. { 33. int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; 34. //char *arr[] = {"aaaa","dddd","cccc","bbbb"}; 35. int i = 0; 36. bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp); 37. for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) 38. { 39. printf("%d ", arr[i]); 40. } 41. printf("\n"); 42. return 0; 43. }