数据的混合运算
数据有不同的类型,不同类型数据之间进行混合运算时必然涉及到类型的转换问题,转换的方法有两种:
自动转换:
遵循一定的规则,由编译系统自动完成。
强制类型转换:
把表达式的运算结果强制转换成所需的数据类型
自动转换的原则:
1.占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低。
2.转换方向:
案例:有符号 和 无符号的转换
#include<stdio.h>
void test01()
{
int data1 = -20;
unsigned int data2 = 10;
//有符号data1和无符号data2参加计算的时候 会将data1转换为无符号(-20的补码很大的正数)
//很大的数 + 10 必然 >0
if(data1 + data2 > 0 )
{
printf(">0\n");
}
else if (data1 + data2 < 0)
{
printf("<0\n");
}
}
int main(int argc,char *argv[])
{
test01();
return 0;
}
运行结果:>0
案例:int double的类型转换
#include<stdio.h>
void test02()
{
int data1 = 10;
printf("%d\n",sizeof(data1+3.14));//8字节
}
int main(int argc,char *argv[])
{
test02();
return 0;
}
案例:short和char类型转换
#include<stdio.h>
void test03()
{
char ch = 'a';
short data = 20;
//由于char、short自身字节数过小,很容易溢出
//只要char、short参加运算 都会将自身转换为int
printf("%d\n",sizeof(ch + ch));
printf("%d\n",sizeof(ch + data));
printf("%d\n",sizeof(data + data));
}
int main(int argc,char *argv[])
{
test03();
return 0;
}
强制类型转换
(类型说明符)(表达式)
功能:把表达式的运算结果强制转换成类型说明符所表示的类型
例如:
(float)a; //把a的值转换为实型
int(x+y);//把x+y的结果值转换为整型
注意:类型说明符必须加括号
案例:强制类型转换代码
#include<stdio.h>
void test04()
{
float x = 3.14f;
int j = 0;
//强制类型转换,只是临时的转换,当前语句有效,在后面的语句中不好更改x的值
j = (int)x;//赋值类型由接受方j决定
printf("j = %d,x = %f\n",j,x);//输出 j = 3,x = 3.140000
}
int main(int argc,char *argv[])
{
test04();
return 0;
}
运行结果:j = 3,x = 3.140000
运算符
用算数运算符将运算对象(也称操作数)连接起来、符合C语法的规则的式子,称为C算数表达式
运算对象包括常量、变量、函数等
例如:a*b / c-1.5 + 'a'
C语言常用运算符
- 算数运算符: + 、1 、*、 /、 %
- 关系运算符: >< 、== 、>= 、<= 、!=
- 逻辑运算符: !、&&、||
- 位运算符: << 、>> 、& 、| 、~ 、^
- 复制运算符: =及其扩展赋值运算符
- 条件运算符: ?:
- 逗号运算符: ,
- 指针运算符:*和&
- 求字节数运算符:sizeof(类型或变量)
- 强制类型转换运算符:(变量或常量)
- 分量运算符:. ->
- 下标运算符:[]
- 其他:如函数调用运算符()
知识点
/ 取整 a/b(a和b必须都为整数)
% 取余 a%b(a和b必须都为整数)
#include<stdio.h>
void test05()
{
printf("%d\n",5/2);//取整 2
printf("%d\n",5%2);//取余 1
}
int main(int argc,char *argv[])
{
test05();
return 0;
}
运行结果:
2
1
Press any key to continue
案例:键盘输入一个输,是否能被3整除
#include<stdio.h>
void test07()
{
//键盘输入一个int数
int num = 0;
printf("请输入一个整型数据:");
scanf("%d",&num);
//判断是否能被3整除
if(num%3==0)
{
printf("可以被3整除\n");
}
else
{
printf("不能被3整除\n");
}
}
int main(int argc,char *argv[])
{
test07();
return 0;
}
输出结果:
请输入一个整型数据:6
可以被3整除
Press any key to continue
课后练习:键盘输入一个4位数,请取出每位上的数值
void test09()
{
printf("%d\n",5/2);//取整
printf("%f\n",5/2.0f);//除
}
运行结果:
#include<stdio.h>
void test08()
{
int num = 0;
printf("请输入一个四位数整数:");
scanf("%d",&num);
if(num <= 999 || num >= 9999)
{
printf("您输入的不是一个四位数整数,请重新执行程序\n");
}
else
{
printf("第一位数:%d\n",num/1000);
printf("第二位数:%d\n",(num%1000)/100);
printf("第三位数:%d\n",(num%100)/10);
printf("第四位数:%d\n",num%10);
}
}
int main(int argc,char *argv[])
{
test08();
return 0;
}
逻辑运算符
! 逻辑非 !0 == 真 !真 == 假
#include<stdio.h>
void test10()
{
printf("%d\n",!1);//0
printf("%d\n",!0);//1
//C语言中 0为假 其他都为真
printf("%d\n",!-1);//0
}
int main(int argc,char *argv[])
{
test10();
return 0;
}
运行结果:
0
1
0
Press any key to continue
逻辑与 &&
A && B AB同时为真 整个表达式为真。 AB中只要有一个为假,则整个表达式为假
#include<stdio.h>
void test11()
{
if( (1>2) && (5>4) )
{
printf("ok\n");
}
else
{
printf("no\n");
}
}
int main(int argc,char *argv[])
{
test11();
return 0;
}
运行结果为:no
逻辑&&短路特性:
A&&B 如果A为假,系统不会执行B 这就是&&的短路特性
#include<stdio.h>
void test12()
{
int num = 10;
printf("比较之前num = %d\n",num);
2 > 3 && (num = 100);
printf("比较之后num = %d\n",num);
}
int main(int argc,char *argv[])
{
test12();
return 0;
}
运行结果:
比较之前num = 10
比较之后num = 10
Press any key to continue
逻辑或 ||
A||B 只有A、B任意一个为真,整个表达式为真。A、B同时为假,结果才为假
逻辑||也有短路特性:只要A为真,编译器不会判断B的真假
#include<stdio.h>
void test13()
{
int num = 10;
printf("比较之前num = %d\n",num);
3 > 1 || (num = 100);
printf("比较之后num = %d\n",num);
}
int main(int argc,char *argv[])
{
test13();
return 0;
}
运行结果:
比较之前num = 10
比较之后num = 10
【位运算符】二进制位操作(重要)
&:按位与
语法:全1为1 其他为0
1010 1010
& 1111 0000
----------------
1010 0000
特点:和1相与保持 不变,和0相与 清零
应用场景:将固定位清零。
|:按位或
语法:有1就为1,全0才为0
1010 1010
| 1111 0000
----------------
1111 1010
特点:和0相或 保持不变,和1相或 置1
应用场景:将固定位置1
案例:将1010 1010的第2、3位置1,其他位保持不变
1010 1010
| 0000 1100
----------------
1010 1110
注意:二进制数的位数是从右到左开始编号的,通常第一个位称为第零位(0位
~:按位取反
语法:0变1 1变0
~1010 1010 == 0101 0101
应用场景:配合&|操作
^:按位异或
语法:相同为0,不同为1
1010 1010
^ 0000 1111
-----------------
1010 0101
特点:与0异或保持不变,和1异或取反
应用场景:将固定的位发生高低电频翻转
案例:将1010 1010 的第0位发生反转
1010 1010
^ 0000 0001
------------------
1010 1011
<<左移运算符:左边丢弃,右边补0
注意:移动的位数 不要超过 自身长度
1010 1100 << 2
>>右移运算符:
1010 1100 >>2
右移分类:逻辑右移 算术右移
逻辑右移:右边丢弃,左边补0
算术右移:
无符号数:右边丢弃,左边补0
有符号数:
正数:右边丢弃,左边补0
负数:右边丢弃,左边补1
右移基本上是右边丢弃左边补0,只有负数且算术右移 左边才会补1.
逻辑右移和算术右移 是编译器决定,但是我们可以检测
作业:自己写代码 判断你的编译器 是逻辑右移还是算术右移?
综合训练:
#include<stdio.h>
//将data的1、5清0,第3、4位 置1, 其他位保持不变
void test15()
{
unsigned char data = 0xaa; //1010 1010
//将data的1、5清0
//1101 1101 = ~(0010 0010) = ~(0010 0000 | 0000 0010)
//0010 0000 = 0000 0001 << 5
//0000 0010 = 0000 0001 << 1
//1101 1101 = ~(0x01<<5|0x01<<1)
data = data & ~(0x01<<5|0x01<<1);
//第3、4位置1:
//data = data|0001 1000;
//0001 1000 = 0001 0000|0000 1000
// = 0x01<<4|0x01<<3
data = data |(0x01<<4|0x01<<3);
}
int main(int argc,char *argv[])
{
test14();
return 0;
}
知识点 三目运算符 ?:
表达式1 ? 值1:值2
语法:如果表达式1为真 整个表达式的值为“值1”否则为“值2”
案例:
#include<stdio.h>
void test16()
{
int ret = 0;
ret = 3>2?5:6;
printf("ret = %d\n",ret);
}
int main(int argc,char *argv[])
{
test16();
return 0;
}
输出结果:ret = 5
Press any key to continue
逗号运算符:
案例:
#include<stdio.h>
void test17()
{
int data1 = 0;
int data2 = 0;
data1 = 3,4,5,6;
data2 = (3,4,5,6);
printf("data1 = %d\n",data1); //输出3
printf("data2 = %d\n",data2); //输出6
}
int main(int argc,char *argv[])
{
test17();
return 0;
}
复合运算符
+= -= *= /= %= 等等
a += b; ==> a = a +b;
a *=b; ==> a = a * b;
注意: =号 的右边必须看成一个整理
#include<stdio.h>
void test18()
{
int data = 3;
//将=号 右边看成一个整体
data *=3+5; //data = data * (3+5)
printf("data = %d\n",data);
}
int main(int argc,char *argv[])
{
test18();
return 0;
}
自增、自减运算符 【++ -- 运算符】
++i 或者 --i 先 加、减 后使用
i++ 或者 i-- 先使用,后加、减
代码案例:
#include<stdio.h>
void test19()
{
int i=3;
int j=0;
//++左边 先加 后使用
j = ++i; // i = i+1; j=i;
printf("i == %d,j == %d\n",i,j);//输出结果 i == 4,j == 4
}
int main(int argc,char *argv[])
{
test19();
return 0;
}
案例:
#include<stdio.h>
void test28()
{
int i = 3;
int j = 0;
j = i++;
printf("i = %d,j = %d\n",i,j);
}
int main(int argc,char *argv[])
{
test28();
return 0;
}
注意:i++ 或 ++i 作为单独的指令 没有区别
运算符的优先级:
C语言中,运算符的优先级共分15级。
1级最高,15级最低。
优先级较高的先于优先级降低的进行运算
在一个运算量两侧的运算符优先级相同时,则按运算符的结合性所规定的结合方向处理。
各运算符的结合性:
- 左结合性(从左至右):+-*/
- 右结合性(从右至左):= ++ --
自己写代码,尽量加()
|