交换两数
使用第三方变量
int a;
int b;
int temp;
temp=a;
a=b;
b=temp;
这样就可以实现两数的交换,但是这也是最简单的方法
如果不能使用第三方变量
我们该如何解决这个问题
四则运算法: //a:10 b=20
加法:a=a+b; b=a-b; a=a-b; //a:20 b=10
减法:a=a-b; b=a+b; a=b-a; //a:20 b=10
乘法:a=a*b; b=a/b; a=a/b; //a:20 b=10
除法:a=a/b; b=a*b; a=b/a; //a:20 b=10
这是我们可以第一时间可以选择四则运算,但是四则运算法会有明显的缺点
四则运算法:
1.没有第三方变量方法直观
2.存在数据溢出问题
3.操作数不能出现0,如果出现0,则乘法和除法不能使用
然后我们可以考虑位运算和一些特殊函数
例如
关于a和b进行交换,不让使用第三方变量,四则运算法不让使用,而且操作数里里面有0怎么求?
异或法: a=a^b; b=a^b; a=a^b; //a:10 b=20
//10: 0000 1010 -> 0001 1110 -> 0001 0100
//20: 0001 0100 -> 0000 1010
虽然异或法的优势很大,但是他依旧有缺点
异或法相较于四则运算法中的乘法和除法,可以让出现0的情况处理掉,而且不存数据溢出问题
缺点:变得更加晦涩难懂
异或法存在一个最主要的问题,因为它是位运算,所以没有办法处理浮点值,那么如果交换的数中存在浮点值怎么办?
如果不了解位运算的原理,那么就很难懂,其次无法对浮点型的数进行操作,所以我们还要使用别的方法
memcpy函数
void My_Swap2_2(int *a, int *b)
{
char tmp[10];
memcpy(tmp, a, sizeof(*a));
memcpy(a, b, sizeof(*b));
memcpy(b, tmp, sizeof(*a));
}
这个函数也可以实现两数的交换,但是实质上还是使用了第三方变量
所以交换两数的其他方法我们考虑到四则运算和异或运算就可以适应大部分的情况
a和b进行比较
当然最简单的方法就是使用各种循环
int MyMax(int a, int b)
{
return a>b ? a : b;
}
int MyMax1(int a, int b)
{
if(a>b)
{
return a;
}
else
{
return b;
}
}
int MyMax2(int a, int b)
{
while(a>b)
{
return a;
}
return b;
}
当然,三目运算符也是一种很简便的方法
那么我们不能使用这些还有什么方法呢
int MyMax3_1(int a, int b)
{
return ((a+b)+(abs(a-b)))/2;
}
int MyMax3_2(int a, int b)
{
bool tag = a>b; //true:1 false:0
int max = tag*a+(1-tag)*b; //a>b a // a<b b
return max;
}
这两种方法的入手角度就很值得我们思考,第一种是大数加小数再加上两者的差值,这就是两杯的大数,然后再除二,就可以得到a,b种较大的数
第二个方法就很巧妙
我们返回bool类型的值,然后数学公式推导出较大的数
类型转换
隐式类型转换:编译器自动将左右操作数变成相同的类型去计算
显式类型转换:开发者主观上去将类型强制转换
C89:
整型类型:char,short,int,long,long long(unsigned signed)
小数类型:float,double,long double
类型转换一般发生在哪里?
//1.赋值语句
//2.算数运算符和逻辑表达式
//3.函数传递的实参和函数的形参匹配的时候
//4.函数返回值和返回值类型匹配的时候
1.如果左右操作数没有浮点值(全是整型值)
1.1 如果操作数小于int类型,则默认先提升类型至int类型 if(a>b),a(char) b(short) => if((int)a>(int)b)
1.2 如果操作数不小于int类型,则小到大转换即可
int < long <long long => int < unsigned int < long < unsigned long < long long < unsigned long long
2.如果左右操作数有浮点值
整型值转换成浮点值 float->double
int main()
{
unsigned char a = 0xA5; //1010 0101
unsigned char b = ~a >> 4+1; //(int)a-> 0000 0000 0000 0000 0000 0000 1010 0101
//~(0000 0000 0000 0000 0000 0000 1010 0101) >> 5
// 1111 1111 1111 1111 1111 1111 0101 1010 >> 5
// 1111 1 1111 1111 1111 1111 111 1 1111 010
printf("b = %d\n", b);
return 0;
}
//A 245
//B 246
//C 250
//D 2
数组指示器
int main()
{
int arr[10] = { 0,0,2,0,0,5,0,0,8,0 };
int brr[10] = {[2]=2, [5]=5, [8]=8};//剩余没有赋值的,默认为0
Show(arr, sizeof(arr) / sizeof(arr[0]));
Show(brr, sizeof(brr) / sizeof(brr[0]));
int crr[10] = { [1 + 1] = 2,[7 - 2] = 5,[3 * 3] = 8 };
Show(crr, sizeof(crr) / sizeof(crr[0]));
int drr[] = { 0,0,2,0,0,5,0,0,8,0 };
Show(drr, sizeof(drr) / sizeof(drr[0]));
int err[] = { [2] = 2,[5] = 5,[8] = 8 };//根据数组指示器最大值进行推演数组长度
Show(err, sizeof(err) / sizeof(err[0]));
int frr[] = { [2] = 2,[5] = 5,[2 * 7] = 14 };
Show(frr, sizeof(frr) / sizeof(frr[0]));
int grr[] = { [5] = 5,[2 * 7] = 14,[2] = 2 };
Show(grr, sizeof(grr) / sizeof(grr[0]));
int hrr[10] = { 1,2,3,[4] = 4,6,[8] = 8 };
Show(hrr, sizeof(hrr) / sizeof(hrr[0]));
//hrr 1 2 3 0 4 6 0 0 8 0
int lrr[] = { 5,1,9,[0] = 1, 3,7,[2 * 7] = 6, 7, 8,[2] = 3 };
Show(lrr, sizeof(lrr) / sizeof(lrr[0]));
//lrr 1 3 3 0 0 0 0 0 0 0 0 0 0 0 6 7 8
return 0;
}
数值指示器是一个小的知识点,我们只需要了解即可
指针结合
float (**def)[10]; //def 是一个二级指针,指向一个一维数组的指针,数组的元素都是float
double *(*gh)[10];//gh 是一个一级指针,指向一个一位数组,这个数组的元素都是double*
double (*f[10])();//f是数组,有10个元素,每一个元素都是函数的指针,指向的函数类型都是美哦与参数且返回值是double的函数
int *((*b)[10]); //b是一级指针,指向一个一维数组,且数组中元素都是int*
int (*fun)(int);//fun是一个函数指针,指向的函数是只有一个int参数且返回值也是int的函数
int (*(*F)(int, int))(int);//F是一个函数指针,这个函数指针是有两个int参数,