-
目录
1.算术操作符
+ - * / %
/
整数的除法 1/2->0
浮点数的除法 1.0/2->0.5
若想用/实现浮点数除法则/号两边至少有一个小数
%:计算的是整除后的余数,取模操作符的的两端必须是整数
2.移位操作符
>>右移操作符
<<左移操作符 移动的是二进制位
移位操作符只针对整型数
ps:正的整数的原码·反码·补码相同;负的整数的原码·反码·补码需要计算
反码 : 原码最高位不动,其余位按位取反得到反码
补码 : 反码加1,得到补码
整数在内存中存的是补码
二进制在整数中的三种形式
//7
00000000000000000000000000000111//原码 最高位为0表示整数
00000000000000000000000000000111//反码
00000000000000000000000000000111//补码
//-7
10000000000000000000000000000111//原码 最高位为1表示负数
11111111111111111111111111111000//反码 原码最高位不动,其余位按位取反得到反码
11111111111111111111111111111001//补码 反码加1,得到补码
//整数在内存中存的是补码
#include<stdio.h>//左移操作符
int main()
{
int a=7;
int b=a<<1;//左边丢弃,右边补零
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
7
14
--------------------------------
Process exited after 0.00511 seconds with return value 0
请按任意键继续. . .
#include<stdio.h>//右移操作符
int main()
{
int a=7;
int b=a>>1;
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
7
3
--------------------------------
Process exited after 0.07812 seconds with return value 0
请按任意键继续. . .
右移操作符分为
算数位移:右边丢弃,左边补原符号位
逻辑位移:右边丢弃,左边补零 采用的位移方式取决于编辑器
值得注意的是对于位移操作符,不要移动负数位,这个是标准位定义的
3.位操作符(只适用于整形)
&:按(2进制)位与 |:按(2进制)位或 ^:按(2进制)位异或
&:对应的2进制位按位与,两个二进制位中如果有0,则对应的结果为0,同时为1时按位与的结果才为1
|:对应的2进制为只要有1则为1,两个同时为0时才为0
^:相同为0,相异为1
#include<stdio.h>//按与的认识
int main()
{
int a=3;
//00000000000000000000000000000011-- 3的补码
int b=-5;
//11111111111111111111111111111011-- 5的补码
int c=a&b;
//对应的2进制位按位与,两个二进制位中如果有0,则对应的结果为0,同时为1时按位与的结果才为1
//所以c的2进制为
//00000000000000000000000000000011
printf("%d\n",c);
return 0;
}
3
--------------------------------
Process exited after 0.08177 seconds with return value 0
请按任意键继续. . .
#include<stdio.h>//按位或的认识
int main()
{
int a=3;
int b=-5;
int c=a|b;//对比3与-5的补码,对应的2进制为只要有1则为1,两个同时为0时才为0
//00000000000000000000000000000011---3的补码
//11111111111111111111111111111011--- -5的补码
//11111111111111111111111111111011---对应的a|b的二进制(补码)
//11111111111111111111111111111010---c的原码
//10000000000000000000000000000101---对应的反码
printf("%d\n",c);
return 0;
}
-5
--------------------------------
Process exited after 0.07843 seconds with return value 0
请按任意键继续. . .
#include<stdio.h>//异或的认识
int main()
{
int a=3;
int b=-5;
int c=a^b;//相同为0,相异为1
//00000000000000000000000000000011---3的补码
//11111111111111111111111111111011--- -5的补码
//11111111111111111111111111111000--- 对应的补码
//11111111111111111111111111110111--- 对应的反码
//10000000000000000000000000001000--- 对应的原码。即打应的值
printf("%d\n",c);
return 0;
}
-8
--------------------------------
Process exited after 0.08288 seconds with return value 0
请按任意键继续. . .
关于^的运用(不创建变量,实现交换两个变量的值)
int a=3; 3^3=0 0^5=5 则3^3^5=5
int b=5; (二进制的后三位) 011 000 3^5^3=5
a=a^b; a=3^5 011 101 可知^支持交换律
b=a^b;3^5^5----b=3 000 101
a=a^b;3^5^3----a=5
4.赋值操作符(=)
区分赋值与初始化
int a=0//初始化
a=999//赋值
赋值可以连续使用
int a=10;
int x=0;
int y=20;
a=x=y+1;//分两步1 x=y+1
2 a=x
复合赋值符
+= -= *=…………………………
int a=1; a+=b; 等价于 a=a+b
int b=9;
5.单目操作符
目录
单目操作符:只有一个操作数
! 逻辑取反
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度
~ 对一个数的二进制按位取反
-- 前置`后置--
++ 前值·后置++
* 间接访问操作符(解引用操作符)
(类型) 强制转换类型
关于单目操作符的理解
---------------------------------------
!的理解
#include<stdio.h>
int main()
{
int flag=3;
if(flag)//flag为真进入
{
}
if(!flag)//flag为假进入
{
}
return 0;
}
---------------------------------------
-的理解
#include<stdio.h>
int main()
{
int a=-10;
int b=-a;
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
-10
10
Process exited after 0.08284 seconds with return value 0
请按任意键继续. . .
---------------------------------------
&的理解
#include<stdio.h>
int main()
{
int a=-10;
printf("%p\n",&a);//取出变量在内存中的起始地址
return 0;//可知a占4个字节,而&a只是取出了第一个字节的地址
}
000000000062FE1C
Process exited after 0.07649 seconds with return value 0
请按任意键继续. . .
---------------------------------------
sizeof的理解(计算的是变量所占内存空间的大小,单位是字节)
ps:sizeof是操作符不是函数
#include<stdio.h>
int main()
{
int a[]={1,2,3,4,5,6,7,8,9,0};
printf("%d\n",sizeof(a));//存放数组名时,计算的是整个数组的大小
return 0;
}
40
Process exited after 0.0728 seconds with return value 0
请按任意键继续. . .
---------------------------------------
~的理解
#include<stdio.h>
int main()
{
int a=0;//~是二进制按位取反
//00000000000000000000000000000000-----补码
//11111111111111111111111111111111----->~a
//11111111111111111111111111111110----->~a反码
//10000000000000000000000000000001----->~a的原码
printf("%d\n",~a);
return 0;
}
-1
Process exited after 0.1595 seconds with return value 0
请按任意键继续. . .
~的应用
#include<stdio.h>
int main()
{
int a=13;//~是二进制按位取反
//00000000000000000000000000001101 把第二位0改成一
//00000000000000000000000000000010理解为1<<1 a按位或1<<
//00000000000000000000000000001111 即可完成对第二位的改变
//对其中的某一个为该变的时候,可以对要改变位数按位或上1<<n,n位要改变的位数
a|=(1<<2);
printf("%d\n",a);
return 0;
}
13
Process exited after 0.2208 seconds with return value 0
请按任意键继续. . .
---------------------------------------
对++于--的理解
#include<stdio.h>
int main()
{
int a=3;
int b=++a;//前置++,先++后使用
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
4
4
Process exited after 0.1716 seconds with return value 0
请按任意键继续. . .
#include<stdio.h>
int main()
{
int a=3;
int b=a++;//后置++,先使用后 ++
printf("%d\n",a);
printf("%d\n",b);
return 0;
}
4
3
Process exited after 0.176 seconds with return value 0
请按任意键继续. . .
---------------------------------------
对*(解引用操作符)的理解
#include<stdio.h>
int main()
{
int a=10;
int *p=&a;//p的类型为int*,是一个指针变量
*p=20;//对p进行解引用,或者说通过p里面的地址找到他所指向的对象
printf("%d\n",a);
return 0;
}
20
Process exited after 0.1633 seconds with return value 0
请按任意键继续. . .
---------------------------------------
对()强制类型转换的理解
#include<stdio.h>
int main()
{
//int a=3.14;类型不一致可能会丢失数据
int a=(int)3.14;
printf("%d\n",a);
return 0;
}
3
Process exited after 0.1763 seconds with return value 0
请按任意键继续. . .
对*的扩展,或者说*p等价于a
6.关系操作符
目录
>
>=
<=
!= 用于测试不相等
== 用于测试相等
if('abc'=='abcdefg')//这样写并不是在比较两个字符串的内容,这样写是在比较这两个字符串的地址
两个字符串比较相等应该用库函数strcmp()
7.逻辑操作符
&&:逻辑与
||:逻辑或
#include<stdio.h>
int main()
{
int a=9;
int b=0;
int c=a&&b;//a或b都为真时结果为真
int d=a||b;//a或b有一个为真时结果为真
//引用&&或||时只有两种结果0(假)和1(真)
printf("%d%d\n",c,d);
return 0;
}
#include<stdio.h>//关于&&的理解
int main()
{
int i=0,a=0,b=2,c=3,d=4;
i=a++&&++b&&d++;//当有结果为0的表达式出现时,后面就都不会继续运行
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
return 0;
}
a=1
b=2
c=3
d=4
--------------------------------
Process exited after 0.1574 seconds with return value 0
请按任意键继续. . .
#include<stdio.h>//对||的理解
int main()
{
int i=0,a=1,b=2,c=3,d=4;
i=a++||++b||d++;//当有结果为1的表达式出现时,后面就不继续运行
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
return 0;
}
a=2
b=2
c=3
d=4
--------------------------------
Process exited after 0.06952 seconds with return value 0
请按任意键继续. . .
8.条件操作符
表达式1?表达式2:表达式3
若表达式1为真,则计算表达式2,表达式3跳过
若表达式1为假,则计算表达式3,表达式2跳过
(a>5?b=3:b=-3)
等价于
if(a>5)
b=3;
else
b=-3;
可以用条件表达式来比较两个数的大小
9.逗号表达式
(就是用逗号隔开的的多个表达式)
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果
#include<stdio.h>
int main()
{
int a=1;
int b=2;
int c=(a>b,a=b+10,b=a+1);
printf("a=%d\nb=%d\nc=%d\n",a,b,c);
return 0;
}
a=12
b=13
c=13
--------------------------------
Process exited after 0.07875 seconds with return value 0
请按任意键继续. . .
if(a=b+1,c=a/2,d>0)//起作用的是左后一个语句,但a=b+1,c=a/2也会计算,并改变a于c的值
10.下标引用,函数调用和结构成员
int a[10]={0};
a[7]=8;//[]为操作符,下标引用
a即数组首元素的地址
a+7即跳过7个元素,指向了第8个元素
a[7]等价于*(a+7)等价于*(7+a)等价于7[a]
----------------------------------------------
int add(int x,int y)
{
//函数定义
return x+y;
}
int main()
{
int a=10;
int b=20;
//函数调用
int c=add(a,b);//()就是函数调用操作符
return 0;
}
----------------------------------------------
#include<stdio.h> //关于结构成员操作符
#include<string.h>
struct stu
{
char name[20];
int age;
double score;
};
void set_stu(struct stu* ps)
{
(*ps).age=20;//等价于ps->age=20;
strcpy((*ps).name,"zhangsan");//strcpy(ps->name,"zhangsan");
(*ps).score=100.0;//ps->score=100.0;
}
void print_stu(struct stu ss)
{
printf("%s %d %lf\n",ss.name,ss.age,ss.score);
}
int main()
{
struct stu s={0};
set_stu(&s);
print_stu(s);
return 0;
}
11.表达式求值
1.隐式类型转换
c语言的整形算数总是至少以缺省整形的精度来进行的,为了获得这个精度,表达式中的字符和短整型操作数在使用前被转换为普通整形,这种转换称为整形提升
以下的例题为字节大小小于整形的类型(char)(short)
#include<stdio.h>
int main()
{
char a=5;
char b=126;
char c=a+b;//char类型的大小达不到一个整形字节的大小,在进行计算时先将变量a,b转换为整形再参与运算
return 0;
}
如何进行整形提升?
(整形提神时按照变量的数据类型的符号来提升的)
#include<stdio.h>
int main()
{ char c=-1;
//-1本身是整数拥有4个字节,32个比特位
//-1的原码10000000000000000000000000000001
//-1的反码11111111111111111111111111111110
//-1的补码11111111111111111111111111111111
//11111111是存放在c中的二进制(从右边开始,取出8个比特位)
//在计算时要进行整形提升,最高位为符号位,符号位为1表示为负数,为0表示正数
// 整形提升时在高位补充符号位
//提升后的c 11111111111111111111111111111111
return 0;
}
ps(对于整数类型,在内存中存储的都是它的补码,而字符类型也归类于整形,原因是:字符在存储的时候存的是它的ASCII码值,ASCII码值是整数)
关于整形提升的例题
#include<stdio.h>
int main()
{
char a=5;
//00000000000000000000000000000101--5的补码
//00000101--a中存储的5的二进制
char b=126;
//00000000000000000000000001111110--126的补码
//01111110 --b中存储的123的二进制
char c=a+b;
//a+b达不到一个整形的大小,进行整形提升
//提神后的二进制 a:00000000000000000000000000000101
//b:00000000000000000000000001111110
//a+b:00000000000000000000000010000011
//c中也是只能存储8个比特位
//c:10000011
printf("%d\n",c);
return 0;
}
-125
--------------------------------
Process exited after 0.1791 seconds with return value 0
请按任意键继续. . .
ps:无符号整形提升,高位补0
#include<stdio.h>
int main()
{
char c=1;
printf("%u\n",sizeof(c));
printf("%u\n",sizeof(+c));//+c为表达式,表达式在使用时发生整形提升
printf("%u\n",sizeof(-c));
return 0;
}
1
4
4
--------------------------------
Process exited after 0.156 seconds with return value 0
请按任意键继续. . .
2.算数转换(若类型的大小大于等于整形)
如果某个操作数的各个操作数属于不同的类型,那么除非其中一个操作数的转换位另一个操作数
的类型,否则操作就无法进行,下面的层次体系称为寻常算数转换
ps:转换是向上转换的(向大的转换),例如float类型与int类型,会把int类型转换为float类型,再比如,float类型与double类型,会把float类型转换为double类型
3.操作符的属性
1.操作符的优先级
2.操作符的结合性
//两个相邻的操作符先执行那个?取决于他们的优先级,如果两者的优先级相同,取决于他们的结合性
3.是否控制求值顺序
表 2 列出优先级次序下,所有 C 语言运算符的优先级和结合律。
优先级 | 运算符 | 结合律 | |
---|---|---|---|
1 | 后缀运算符:[] () · -> ++ --(类型名称){列表} | 从左到右 | |
2 | 一元运算符:++ -- ! ~ + - * & sizeof_Alignof | 从右到左 | |
3 | 类型转换运算符:(类型名称) | 从右到左 | |
4 | 乘除法运算符:* / % | 从左到右 | |
5 | 加减法运算符:+ - | 从左到右 | |
6 | 移位运算符:<< >> | 从左到右 | |
7 | 关系运算符:<<= >>= | 从左到右 | |
8 | 相等运算符:== != | 从左到右 | |
9 | 位运算符 AND:& | 从左到右 | |
10 | 位运算符 XOR:^ | 从左到右 | |
11 | 位运算符 OR:| | 从左到右 | |
12 | 逻辑运算符 AND:&& | 从左到右 | |
13 | 逻辑运算符 OR:|| | 从左到右 | |
14 | 条件运算符:?: | 从右到左 | |
15 | 赋值运算符: = += -= *= /= %= &= ^= |= <<= >>= | 从右到左 | |
16 | 逗号运算符:, | 从左到右 |
关于问题表达式(没有办法确定唯一的计算路径)
#include<stdio.h> //问题表达式的例子,以下代码在不同的编译器的运行结果是不同的
int main()
{
int i=10;
i=i-- - --i * (i = -3) * i++ + ++i;
printf("%d\n",i);
return 0;
}
//以下程序也是一个问题表达式
#include<stdio.h>
int fun()
{
int count =1;
return ++count;
}
int main()
{
int i=10;
i=fun()-fun()*fun;//无定法确定先调用那个函数
printf("%d\n",i);
return 0;
}