1,函数指针数组的用途:转移表
1.1举例:计算器的一般实现
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
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()
{
int x, y;
int input = 1;
int ret = 0;
do
{
printf("***************************\n");
printf("1.add 2.sub\n");
printf("3.mul 4.div\n");
printf("***************************\n");
printf("请选择:\n");
scanf_s("%d", &input);
switch (input)
{
case 1:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("exit\n");
break;
default:
printf("选择错误\n");
break;
}
printf("\n");
} while (input);
}
1.2使用函数指针数组的实现
#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()
{
int x, y;
int input = 1;
int ret = 0;
int(*p[5])(int x, int y) = { 0,add,sub,mul,div };
do
{
printf("***************************\n");
printf("1.add 2.sub\n");
printf("3.mul 4.div\n");
printf("***************************\n");
printf("请选择:\n");
scanf_s("%d", &input);
if (input <= 4 && input >= 1)
{
printf("请输入操作数:");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);
printf("ret=%d\n", ret);
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输入错误\n");
}
} while (input);
return 0;
}
1.3 相关知识点
1.3.1函数指针数组定义
int (*parr1[3])();
parr1先于[ ]结合,说明parr1是数组,数组的内容是int(*)()类型的函数指针
1.3.2函数指针数组的应用
int(*p[5])(int x, int y) = { 0,add,sub,mul,div };
函数指针函数可以直接调用函数,简化了代码
2,找两个独立的数
2.1 内容:
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6.
2.2 思路
2.2.1 相关知识点
位操作符(都是要把十进制数转为二进制数来计算):
1,按位与&(同1位1):
例如:a=3,b=-5
3的补码:00000000000000000000000000000011(正数的原码和补码相同)
5的原码:00000000000000000000000000000101
取反 : 11111111111111111111111111111010
-5的补码: 11111111111111111111111111111011
反码+1就是补码
按位与运算结果:00000000000000000000000000000011—>3
2,按位或|:有1则为1
结果:11111111111111111111111111111011 得到-5的补码
3,按位异或^:相同为0,相异为1
4,按位取反~:对每一位二进制数都取反
例如:a=0,b=~a
a: 000000000000000000000000000000000000
b: 11111111111111111111111111111111
负数取反:10000000000000000000000000000000
加一:10000000000000000000000000000001
得到b是-1
2.2.2整体思路:
1,整体异或 结果就是两个不一样的数字的异或结果x
2,找到x的倒数第k位为1的地方
3,把所有数字 以第k位为1 分开进行异或
我们用代码进行进一步的解释:
找出一个只出现过一次的数字的问题处理方法就是找一个数字把里面所有的数字都异或一遍,利用异或两次等于没异或的特点来处理。那么如果有两个数字都只出现了一次,那么如此得到的应该是两个数异或的结果。首先这个结果肯定不是0(要不然就全都配对了),所以里面一定至少一位是一。找出值为1的一位,以这一位的值将结果分为两组。例如1 2 3 4 1 2,异或完的结果应该是3 ^ 4得到的111,那么随便找一位就行了。例如找最低位,那么这一位是1的有1 3 1,是0的有2 4 2,由于是利用异或结果为1的某一位分的组,所以两个待查询数字一定分别在两组中。所以再找两个变量,分别异或两组数,即可找到这两个数。
#include<stdio.h>
void findTwoNum(int arr[], int n, int* pnum1, int* pnum2)
{
int i;
int sum = 0;
for(i = 0; i < 9; i++)
{
sum ^= arr[i];
} //先找到两个不同数互相异或的结果,因为相同的数异或为0,不同的数异或为其他
//如5和6,1和2…………
int pos;
for (i = 0; i < 32; i++)
{
if (sum & 1 << i)//按位与:同一为一
{
pos = i;
break;
}
} //再找到有分歧的一位。在这一位上,两个数一定是一个1一个0
//就比如0110 0111 0001有分歧的是最后一位
* pnum1 = *pnum2 = 0;
for (i = 0; i < 10; i++)//分组异或,组内相同数为0
{
if (arr[i] & 1 << pos)//分组:1 1 4 4 6
{
*pnum1 ^= arr[i]; //这一位是1的,放在数1里
}
else//2 2 3 3 5
{
*pnum2 ^= arr[i]; //这一位是0的,放在数2里
}
}
}
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
int len = sizeof(arr) / sizeof(arr[0]);
int num1 = 0;
int num2 = 0;
findTwoNum(arr, len, &num1, &num2);
printf("%d %d\n", num1, num2);
//int (*p)(int a, int b);
return 0;
}
3,获得月份天数
输入年份和月份,得到该月的天数
#include <stdio.h>
int main()
{
int y = 0;
int m = 0;
int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
while (scanf_s("%d%d", &y, &m) != EOF)
{
int day = days[m - 1];
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
{
if (m == 2)
day += 1;
}
printf("%d\n", day);
}
return 0;
}