函数指针
在C语言中,函数指针是指向函数的指针变量。它可以用来存储和访问函数的地址,从而可以通过函数指针调用相应的函数。
我们先来看一段代码:
#include <stdio.h> void test() { printf("hehe\n"); } int main() { printf("%p\n", test); printf("%p\n", &test); return 0; }
两个都是test函数的地址,想要将test的地址保存到指针里,我们可以这样做:
void test() { printf("hehe\n"); } int main() { printf("%p\n", test); printf("%p\n", &test); void (*pfun)() = test; printf("%p\n", pfun); return 0; }
这样就成功的将test函数地址存到了指针中去。
利用函数指针数组实现简易计算器
相信大家都能够写出一个计算器,所以我们来用函数指针数组来实现一下。
#include<stdio.h> int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a / b; } int main() { printf("*********************\n"); printf("**1.add*******2.sub**\n"); printf("**3.mul*******4.div**\n"); printf("*******0.exit********\n"); int x, y; int input = 1; int (*p[5])(int, int) = { 0,add,sub,mul,div }; int ret = 0; do { printf("请选择操作:"); scanf("%d", &input); if (0 < input && input < 5) { printf("请输入操作数:"); scanf("%d %d", &x, &y); ret = (*p[input])(x, y); printf("%d\n", ret); } else if (input == 0) { printf("退出程序"); } else { printf("输入有误,重新选择"); } } while (input); return 0; }
我们首先将加减乘除四个功能分别封装为四个函数,然后将四个函数的地址,存放到指针p中,为了更好的对应,我们把第一个元素设置为0,之后进入循环,将input作为操作数传参给p指针数组的下标,x和y作为操作数传参给对应的函数将返回值赋给ret,最后打印ret即可得到结果。
指针和数组题测试
我们了解了之后,来看一下我们掌握的怎么样
//一维数组 int a[] = {1,2,3,4}; printf("%d\n",sizeof(a));// 16,数组名单独放到sizeof代表的是整个数组的大小,16个字节 printf("%d\n",sizeof(a+0));// 4/8 并非是单独放到sizeof中所以代表的是数组首元素的地址 printf("%d\n",sizeof(*a));//4,*a代表对首元素地址解引用,也就是1这个数字也就是4byte//*a == *(a+0) == a[0] printf("%d\n",sizeof(a+1));// 4/8代表数组中第二个元素的地址 printf("%d\n",sizeof(a[1]));// 4代表数组中第二个元素 printf("%d\n",sizeof(&a));// 4/8 &a代表a数组的地址,地址的字节是4/8 printf("%d\n",sizeof(*&a));// 16 &a得到数组的地址,后解引用访问整个数组的大小,所以是16 printf("%d\n",sizeof(&a+1));//4/8 &a得到的是地址,+1还是地址所以是4/8 printf("%d\n",sizeof(&a[0]));//4/8 a[0]是首元素,&得到地址所以是4/8 printf("%d\n",sizeof(&a[0]+1));//4/8 得到地址后+1还是地址 //字符数组 char arr[] = {'a','b','c','d','e','f'}; printf("%d\n", sizeof(arr));//6 数组名arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节 printf("%d\n", sizeof(arr+0));//4/8 arr是首元素的地址==&arr[0],是地址就是4/8个字节 printf("%d\n", sizeof(*arr));//1 arr是首元素的地址,*arr就是首元素,大小就是1Byte printf("%d\n", sizeof(arr[1]));//1 数组中第二个元素 printf("%d\n", sizeof(&arr));//4/8 整个数组的地址 printf("%d\n", sizeof(&arr+1));//4/8 整个数组地址+1 printf("%d\n", sizeof(&arr[0]+1));//4/8 数组第一个元素的地址+1,第二个元素的地址 printf("%d\n", strlen(arr));//随机值,arr是首元素的地址 printf("%d\n", strlen(arr+0));//随机值,arr是首元素的地址, arr+0还是首元素的地址 printf("%d\n", strlen(*arr));//err,arr是首元素的地址, *arr就是首元素 - 'a' - 97 printf("%d\n", strlen(arr[1]));//err, 'b' - 98 printf("%d\n", strlen(&arr));//随机值 地址 printf("%d\n", strlen(&arr+1));//随机值 地址 printf("%d\n", strlen(&arr[0]+1));//随机值 地址 char arr[] = "abcdef"; printf("%d\n", sizeof(arr));//7 整个数组的大小包括'\0' printf("%d\n", sizeof(arr+0));//4/8 首元素地址 printf("%d\n", sizeof(*arr));//1 访问数组首元素 printf("%d\n", sizeof(arr[1]));//1 数组中第二个元素 printf("%d\n", sizeof(&arr));//4/8 地址 printf("%d\n", sizeof(&arr+1));//4/8 地址 printf("%d\n", sizeof(&arr[0]+1));//4/8 地址 printf("%d\n", strlen(arr));//6 数组的长度,不包括'\0' printf("%d\n", strlen(arr+0));//6 arr + 0 的类型是指向字符串的指针,strlen(arr + 0) 返回指针指向的字符串的长度,不包括终止符 \0 printf("%d\n", strlen(*arr));//err printf("%d\n", strlen(arr[1]));//err printf("%d\n", strlen(&arr));//随机值 地址 printf("%d\n", strlen(&arr+1));//随机值 地址 printf("%d\n", strlen(&arr[0]+1));//随机值 地址 char *p = "abcdef"; printf("%d\n", sizeof(p));//4/8 地址 printf("%d\n", sizeof(p+1));//4/8 地址 printf("%d\n", sizeof(*p));//1 代表a printf("%d\n", sizeof(p[0]));//1 代表a printf("%d\n", sizeof(&p));//4/8 地址 printf("%d\n", sizeof(&p+1));//4/8 地址 printf("%d\n", sizeof(&p[0]+1));//4/8 地址 printf("%d\n", strlen(p));//随机值 地址 printf("%d\n", strlen(p+1));//随机值 地址 printf("%d\n", strlen(*p));//err printf("%d\n", strlen(p[0]));//err printf("%d\n", strlen(&p));//随机值 地址 printf("%d\n", strlen(&p+1));//随机值 地址 printf("%d\n", strlen(&p[0]+1));//随机值 地址 //二维数组 int a[3][4] = {0}; printf("%d\n",sizeof(a));//48 整个数组的大小,4*12=48 printf("%d\n",sizeof(a[0][0]));//4 首行数组的首元素 printf("%d\n",sizeof(a[0]));//16 首行数组 printf("%d\n",sizeof(a[0]+1));//4/8 首行数组地址+1 printf("%d\n",sizeof(*(a[0]+1)));//4 第一行第二个元素解引用 printf("%d\n",sizeof(a+1));//4/8 未单独放代表地址,+1还是地址 printf("%d\n",sizeof(*(a+1)));//16 a+1是第二行的地址,*(a+1)就是第二行,计算的就是第二行的大小 printf("%d\n",sizeof(&a[0]+1));//4/8 地址 printf("%d\n",sizeof(*(&a[0]+1)));//16 第二行的大小 printf("%d\n",sizeof(*a));a表示数组首元素的地址,也就是第一行的地址 *a 就是第一行,也就相当于是第一行的数组名 *a--> *(a+0) -- a[0] printf("%d\n",sizeof(a[3]));//16
总结
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址
指针题测试
给大家留一个看起来很复杂的指针测试题,相信大家理解了指针后,一定能轻而易举的写出来
int main() { char *c[] = {"ENTER","NEW","POINT","FIRST"}; char**cp[] = {c+3,c+2,c+1,c}; char***cpp = cp; printf("%s\n", **++cpp); printf("%s\n", *--*++cpp+3); printf("%s\n", *cpp[-2]+3); printf("%s\n", cpp[-1][-1]+1); return 0; }
最后吸收一下大家的手气。