1.操作符
①算数操作符 +,-,*,/(除,求商),%(取模,求余数)
一:除了%操作符,其他几个操作符可以用于整数和浮点数。
二:对于/操作符如果两个数都为整数,执行整数除法,而只有有浮点数执行的就是浮点数除法。
三:%操作符的两个操作数必须为整数,返回的是整除后的余数。
int a=5/2;
printf("a=%d\n",a);//a=2
double a=5/2.0;//除数和被除数至少一个浮点数
printf("a=%lf\n",a);//a=2.5
②移(2进制)位操作符 << 左移,>> 右移
右移操作符(右移1位有除2的效果)
1.算数右移(通常都是)
右边丢弃,左边补原符号位
2.逻辑右移
右边丢弃,左边补0
整数的二进制位表示有:原码,反码,补码
整数的三码相同
存储到内存中的是补码
int a=-1;
10000000000000000000000000000001——原码
11111111111111111111111111111110——反码(原码符号位不变,其他位按位取反)
11111111111111111111111111111111——补码(反码+1)
int b=a>>1;//补码右移左边依旧补1,打印原码依旧是-1.
左移操作符(有乘2的效果)
左边丢弃,右边补0.
警告:对于移位操作符,不要移动负数位,该标准未定义
例:int b=a>>-1;//error
③(2进制)位操作符 &(按位与) , |(按位或) , ^(按位异或)
注:它们的操作数必须是整数(移位操作符同样),都是用补码进行运算。
问题1:不创建新变量来交换两个变量,以a=3,b=5为例:
一:加减法
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a + b;//a=8,b=5
b = a - b;//a=8,b=3
a = a - b;//a=5,b=3
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
缺陷:如果a+b超过整型的最大值则不适用
二:异或方法
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
a : 0 1 1 密码:1 1 0 密码:1 1 0
b: 1 0 1 a: 0 1 1 b: 1 0 1
密码1 1 0 1 0 1 0 1 1
密码和b异或翻译出a,密码和a异或翻译出b
问题2:求一个整数存储在内存中的二进制中1的个数
#include <stdio.h>
int main()
{
int num = 0;
int count = 0;
scanf("%d", &num);
int i = 0;
for (i = 0; i < 32; i++)
{
if (1 == ((num >> i) & 1))
count++;
}
printf("%d\n", count);
return 0;
}
num:******** ******** ********
1:00000000 0000000 00000001
num与1按位与,前31位由于1的二进制位都是0,所以按位与后也是0,只有num最低位是1才能按位与后==1,所以要统计32位,不断右移,并循环32次。(负数补位后最右位补得是1,但总共只循环32次,所以不会计入多补出的1。
④赋值操作符 =,+=,-=,/=,&=,^=,|=,>>=,<<=
赋值操作符可以连续使用(但不推荐)
a=x=y+1;//将y+1赋给x,再将x赋给y。
a=a+2;即a+=2;
a=a>>1;即a>>=1;
a=a&1;即a&=1;
⑤单目操作符 ! ,- ,+ ,& ,sizeof ,~ ,-- ,++ ,* ,(类型)
1.!
if(a)
{
printf("hehe\n");
}
//如果a为真打印hehe
if(!a)
{
printf("hehe\n");
}
//如果a为假打印hehe
2.&,*
int a=10;
int *p=&a;//用取地址操作符取出a的值,并存在p中
*p=20;//*解引用操作符,通过p中存的值找到它所指向的对象,*p就是所指向的对象a
3.sizeof:计算变量所占内存空间的大小,单位是字节
int a=10;//4 打印sizeof(a)/sizeof(int)
char c='r';//1 打印sizeof(c)/sizeof(char)
char *p=&c;//32位平台:4,64位平台:8 打印sizeof(p)/sizeof(char*)
int arr[10]={0};//10个元素,每个元素均为int,所以是40 打印sizeof(arr)/sizeof(int[10]),对于数组去掉名字就是类型
#include <stdio.h>
int main()
{
short s = 0;
int a = 10;
printf("%d\n", sizeof(s = a + 5));//2 a是整型,+5后的结果存在s中,s是短整型,最终sizeof看s,结果是2
printf("%d\n", s);//0 sizeof括号后面的表达式不会进行真实运算,所以s的值不变,依旧是0
return 0;
}
⑥关系操作符 > >= < <= != ==
⑦逻辑操作符 &&逻辑与 ||逻辑或
int i=0,a=0,b=2,c=3,d=4;
i=a++&&++b&&d++;
逻辑与操作符,逻辑与左边为假,则此时总体已经为假,右边无论如何都不进行运算,所以不会进行++b,d++,结果a=1,b=2,c=3,d=4
int i=0,a=1,b=2,c=3,d=4;
i=a++||++b||d++;
逻辑或操作符,左边为真,总体已经为真,右边同样不再进行运算,所以没有进行++b,d++,结果a=2,b=2,c=3,d=4
⑧条件操作符 exp1?exp2:exp3;
⑨逗号表达式 exp1,exp2,exp3,...,expN
由逗号隔开的一串表达式.逗号表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1);//a>b和a不产生结果,c=13
if(a=b+1,c=a/2,d>0)//真正起到判断作用的是d>0,成立为真,否则为假
⑩下标引用,函数调动和结构成员 [ ] ( ) . ->
1.[ ] 下标引用操作符
操作数:一个数组名+一个索引值
int arr[10];//创建数组
arr[9]=10;//[]的两个操作数是arr和9
2.()函数调用操作符
接受一个或多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数
int a=10;
int b=20;
int max=get_max(a,b);//调用函数的时候的()就是函数调用操作符
3.访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
#include <stdio.h>
struct Stu//Stu-学生 创建一个结构体类型
{
char name[20];
int age;
char id[20];//成员变量
};
int main()
{
struct Stu s1 = { "张三",18,"20220910" };
printf("%s\n", s1.name);//.的操作数是结构体变量,成员名
printf("%d\n", s1.age);
printf("%s\n", s1.id);
struct Stu* ps1 = &s1;
printf("%s\n", (*ps1).name);
printf("%d\n", (*ps1).age);
printf("%s\n", (*ps1).id);
struct Stu* ps2 = &s1;
printf("%s\n", ps2->name);
printf("%d\n", ps2->age);
printf("%s\n", ps2->id);
return 0;
}