操作符
算数操作符 + - * / %
+ - *(略)
/ 要想保证除后数目为小数则 /号内两个数必须有一个至少是小数。
int main()
{
float num = 6 / 5;
printf("%f", num);//(此时输出为1.000000)
return 0;
}
int main()
{
float num = 6.0 / 5;
printf("%f", num);//(此时输出为1.200000)
return 0;
}
% 可以实现指的数目内的取值,取余的两端必须是整数。
int main()
{
while (1)
{
int a = rand() % 9;
printf("%d", a);//打印的数只会在0-8内
}
return 0;
}
移位操作符<< >>
<< >>元素进行二进制位上的位移(移位操作符并不改变原值)
左移<< 将int a=2<<(左移)1(一位)
int contain 4 bytes,1 byte contains 8 bits
00000000 00000000 00000000 00000010(整型2的二进制)
00000000 00000000 00000000 00000100(左移1位,此时为4)
int main()
{
int a = 2;
int b = a << 2;
printf("%d\n", b);//此时输出为8
return 0;
}
右移>> (逻辑右移和算数右移)
逻辑右移: 右边溢出的抛弃,空缺左边补0
算术右移:右边溢出的抛弃,空缺左边补原符号位
注:使用移位操作符时,不要移动负位,这是非标准写法。//error
位操作符 & | ^
&按位与 有一个0则同位0 2个1同位1(同计算机原理与)
例:int a=3&13
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00001101
00000000 00000000 00000000 00000001
int main()
{
int a = 3 & 13;
printf("%d", a);//输出为1
return 0;
}
|按位或 有一个1同位1 2个0同位0(同计算机原理或)
例: int a=3&13
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00001101
00000000 00000000 00000000 00001111
int main()
{
int a = 3 | 13;
printf("%d", a);//输出为15
return 0;
}
^按位异或 相同为0 不同为1(同计算机原理或)
例: int a=3^13
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00001101
00000000 00000000 00000000 00001110
int main()
{
int a = 3 ^ 13;
printf("%d", a);
return 0;
}
同数异或为0,任何数和0异或都是其本身。
3^3=0
3^0=3
赋值操作符
=
+=(a+=1 a=a+1先加后等) -=、*= 、 /= 、<<=、>>= 、&=、|=、^=…
单目操作符
!逻辑反(0为假则!0为真)
-负值 +正值
&取地址
sizeof操作数的类型长度(字节为单位)
~对一个数的二进制数按位取反
例:
int main()
{
int a = 0;
printf("%d\n", ~a);
//~对一个数的二进制数按位取反
//0的整型二进制数为00000000 00000000 00000000 00000000(在计算机中为补码)
//~a既~0的二进制数为11111111 11111111 11111111 11111111(仍存在于计算机内存中为补码)
//运行显示时为原码,则要进行原反补计算(二进制第一位表示正负)
//对于负数:
//11111111 11111111 11111111 11111111(补码)
//11111111 11111111 11111111 11111110(补码-1=反码)
//10000000 00000000 00000000 00000001(除符号位取反=原码)
//对于正数:原反补相同
return 0;
}
.- -、++ 前置先自算后使用、后置先使用后自算
例:
int main()
{
int a = 8;
int b = ++a;//先自加a=9,后使用b=a=9
int c = 10;
int d = c++;//先使用d=c=10,后自加c=11
printf("%d\n", a);
printf("%d\n", b);
printf("%d\n", c);
printf("%d\n", d);
return 0;
}
解引用操作符*
int main()
{
int a = 10;
printf("%p\n", &a); // & -取地址操作符
int * pa = &a; // pa是用来存放地址的 - pa就是一个指针变量(字节大小为4(32位)/8(64位))
printf("%d", *pa); //*-解引用操作符–间接访问操作符
return 0;
}
(类型) 强制类型转换
int main()
{
int a = (int)13.9;//(强制转化成int)
//error int a = 13.9(浮点型);出现报错
printf("%d\n", a);
return 0;
}
关系操作符
< >
<=小于等于 >=大于等于
!=不等于 ==等于
逻辑操作符
&&逻辑与:与起的所有元素为真则为真,有一为假则为假
||逻辑或 :或起的所有元素有一为真则为真,全为假则为假
条件操作符
exp1 ? exp2 : exp3
判断exp1,真,则计算exp2,整个表达式是exp2的结果
判断exp1,假,则计算exp3,整个表达式是exp3的结果
int main()
{
int a = 1;
int b = 0;
int c = 1;
int d = a = c > b ? a : b;
printf("%d", d);
return 0;
}
逗号表达式:
是从左向右依次计算,整个表达式的结果是最后一个表达式的结果。
(exp1,exp2,exp3,exp4,...,expN)
int main()
{
int data=(4, 5 + 6, 7, 8 + 9);
printf("%d\n", data);
return 0;
}
下标引用操作符[]
int main()
{
int arr[8] = { 1,2,3,4,5,6,7,8 };
printf("%d\n", arr[1]);//中的[]就为下标引用操作符
return 0;
}
函数调用操作符()
int main()
{
printf("you're a fucking cunt\n");//中()就为函数调用操作符。
return 0;
}
结构成员操作符 . ->
结构体:可以创造一些c语言不自带的数据类型,从而来描述复杂对象。
struct + 变量名
{};
struct individual
{
char name[20];
char country[20];
int age;
char sex[5];
float weight;
double height;
};
int main()
{
struct individual I = { "Chris Lin","China",22,"MALE",11.4514,114.514 };//初始化结构体。
printf("Print 1:\n%s\n%s\n%d\n%s\n%f\n%lf\n\n", I.name, I.country, I.age, I.sex, I.weight, I.height);
//结构体变量.结构体成员变量
struct individual* indi = &I;
printf("Print 2:\n%s\n%s\n%d\n%s\n%f\n%lf\n\n", (*indi).name, (*indi).country, (*indi).age, (*indi).sex, (*indi).weight, (*indi).height);
//(*指针变量).结构体成员变量=结构体变量.结构体成员变量
printf("Print 3:\n%s\n%s\n%d\n%s\n%f\n%lf\n", indi->name, indi->country, indi->age, indi->sex, indi->weight, indi->height);
//指针变量->结构体成员变量=(*指针变量).结构体成员变量
return 0;
}
表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。 同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
int main()
{
char a = 3;
//整型提升 00000000 00000000 00000000 00000011
//存入char型a中去,发生截断 00000011
char b = 127;
//整型提升 00000000 00000000 00000000 01111111
//存入char型b中去,发生截断 01111111
char c = a + b;
//整型提升 00000000 00000000 00000000 00000011
//整型提升 00000000 00000000 00000000 01111111
// 00000000 00000000 00000000 10000010
//存入char型c中去,发生截断 10000010
printf("%d", c);
//整型提升 11111111 11111111 11111111 10000010-补码
// 11111111 11111111 11111111 10000001-反码
// 10000000 00000000 00000000 01111110-原码打印
//-126
//负数整型提升补1,正数补0,无符号unsigned补0.
return 0;
}
整型提升的意义
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU (general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
算数转换
操作符属性
1.优先级决定计算顺序
2.优先级起不到作用时,结合性决定计算顺序
3.是否控制求值顺序