1.算数操作符
2.移位操作符
3.赋值操作符
4.单目操作符
5.关系操作符
6.逻辑操作符
7.条件操作符(三目操作符)
8.下标引用,函数调用和结构成员
算数操作符
除号(/)在运算的时候,如果说是5.0/6.0 那么编译器会给他自定义为双精度的类型,即使定义了单精度的浮点型,会被认为是丢失了精度 ,在5.0或6.0后面加一个f,变为5.0f 6.0f 就会解决这个问题
取模(%) 取余 取余的两个数必须是 整数 相除
移位操作符 (后面有较为全面的总结)
左移操作符(<<) 是在n进制中移位 左边丢弃,右边补齐
#include<stdio.h>
int main()
{ //一个字节8比特
int a=3; 00000000 00000000 00000000 00000011 =1*2^1+1*2^0 = 3
int b=a<<2; 00000000 00000000 00000000 00001100 =1*2^3+1*2^2+0*2^1 = 12
printf("%d",b);
return 0;
}
这个是把a的二进制向左移动2位
00000000 00000000 00000000 00000011 =1*2^1+1*2^0 = 3
00000000 00000000 00000000 00001100 =1*2^3+1*2^2+0*2^1 = 12
右移操作符 (>>)
算数右移 右边丢弃,左边补原符号位 (原符号位是1,就补1。是0 就补0) 逻辑右移 右移丢弃,左边补0 (不管原符号位是多少,都要补0) 可能以算数右移为主
原码,反码,补码(正数的原码 反码 补码相同)
原码:直接根据数值写出二进制 10000000 00000000
反码:原码的符号位不变,其他的都按位取反 111111111 111111111 符号不变,其他的取反
补码:就是在最低位置上 加1,0000000000010==0000000000011
位(二进制位)操作符(按位与 & 按位或 | 按位异或^)
按位与:& a b 两个数的二进制,上下对应,有1 和0 对应的时候,只有上下两个不相等就变为0 都是1 的时候才为 1
#include<stdio.h>
int main()
{
int a=3;
int b=5;
int c=a & b;
printf("%d",c);
return 0;
}
得出结果c=1. int a = 3 00000000 00000000 00000000 00000011
int b = 5 00000000 00000000 00000000 00000101
int c = 1 00000000 00000000 00000000 00000001
按位或 : | 两个数的二进制一一对应的时候 如果有1,则为1 如果两个同时为0 的时候则为0
#include<stdio.h>
int main()
{
int a=2;
int b=5;
int c=a|b;
printf("%d",c);
return 0;
}
为c = 7
int a=2 00000000 00000000 00000000 00000010 int b=5 00000000 00000000 00000000 00000101 int c=7 00000000 00000000 00000000 000000111
按位异或:^ 相同则为0 相异则为1
#include<stdio.h>
int main()
{
int a=3;
int b=5;
int c=a^b;
printf("%d",c);
return 0;
}
int a = 3 00000000 00000000 00000000 00000011 int b = 5 00000000 00000000 00000000 00000101 int c= 6 00000000 00000000 00000000 00000110
位操作符的使用方法
在不引用任何变量的情况下,把a=3, b=5交换一下,就是要让a=5 b=3 这种情况下采用按位异或的操作符
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d,%d",a,b);
return 0;
}
具体讲,我就不记了,就是转化为二进制然后在去用按位异或的方法(相同为0,不相同为1)的方法去进行计算。害,背过这个交换就行了 当然,a=a+b ,b=a-b ,a=a-b 这种方法也不是不可以,但是容易溢出,超出他的数据类型,会丢失二进制。
两个相同的数字亦或是0,a ^ a=0 a ^ a ^ a=a
题目 求整数存储在内存中的二进制中的1 有多少个
#include<stdio.h>
int main()
{
int a=13;//00000000 00000000 00000000 00001101
int i; //00000000 00000000 00000000 00000001
int b=0;
for(i=1;i<=4;i++)
{
if(a&1==1)
{
a>>1;
b++;
}
else if(!a&1==1)
{
a>>1;
}
}
printf("%d",b);
return 0;
}
总结:1.按位与 &(有0 就是0) 2. 按位或 | (有1 就是1) 3. 按位异与(相同为0 不同为1)
1 & 1 = 1 1 | 1 = 1 0 ^ 0 = 0
1 & 0 = 0 1 | 0 = 1 1 ^ 1 = 0
0 & 0 = 0 0 | 0 = 0 1 ^ 0 = 1
题目 把13 的二进制中的倒数第二个0变为1,00000000 00000000 00000000 00001101
a = a | (1 << 4 ) 就可以把倒数第二个 0 变为1 1的二进制为00000000 00000000 00000000 00000001
赋值操作符
=(赋值操作符)
覆合操作符 += /= %= &= |= ^= <<= >>=
单目操作符 只有一个操作符
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度
~ 对一个数的二进制取反 全部按位取反
++ --
*
(类型) 强制类型转换
!: int flag=5 printf("%d ",!flag) 结果为 0 因为!flag是假的
sizeof : 在计算变量名的大小的时候,可以省略掉括号,其他的都不可以了
#include<stdio.h>
int main()
{
int a = 10;
printf("%d",sizeof a);
return 0;
}
结果是 4
sizeof( )的括号里面的表达式是不参与运算的 因为sizeof 仅仅只是去算字节而已
#include<stdio.h>
int main()
{
int a = -1;
int b;
b = ~a;
printf("%d",b);
pritnf("%d",a);
return 0;
}
~ 每一个都按位取反的操作符
& 和 * 这两个操作符基本放在一起运算
int *pa = &a (pa 是指针变量,用来存放a的地址) int a * pa的指向类型也应该是int,这个 * 的符号叫做间接访问操作符,通过a里面存的地址,去访问a
#include<stdio.h>
int main()
{
int a;
a = 10;
int *pa = &a; //这里的*pa是 去访问a的空间 ,这里的* 是指针变量
*pa = 20; //把a的空间里的东西去做出改变 ,这里的*是操作符
printf("%d",a);
return 0;
}
int *pa 中的* 是指针变量,,而*pa是操作符 一个指针占4个或8个字节
#include<stdio.h>
test1(int arr[])
{
printf("%d",sizeof(arr));
}
test2(char ch[])
{
printf("%d",sizeof(ch));
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
test1(arr);
test2(ch);
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(ch)); //这里的数组传过去,其实只是传了首元素的地址,只有一个而已
return 0; //一个元素的地址就是一个指针 一个指针的字节是4或者是8
}
(类型) 强制类型转换
#include<stdio.h>
int main()
{
int a=(int)3.14;
printf("%d",a);
return 0;
}
输出结果是3 在3,14前加(int) 去重新定义 会输出3 这个整形
关系操作符
> >= < <= != ==
逻辑操作符
&& || !
&& 左边为假 右边不要算
如果这里面有一个是假的话,那么结果就为0 如x&&y x=0的话,结果是0 后面的就不运算了
#include<stdio.h>
int main()
{
int i=0,a=0,b=2,c=3,d=4;
i = a++ && ++b && d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
return 0;
}
这里运行出来的结果是 1 2 3 4
因为a++是先运行再加1 所以 a刚开始是0 那&& ++b,或者是&& d++ 那就没有什么必要再继续下去了,b 和 d就不用再去费时间运算了 但 a是参与了运算的,所以a++还是要去算的
如果把a改成1
#include<stdio.h>
int main()
{
int i=0,a=1,b=2,c=3,d=4;
i = a++ && ++b && d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
return 0;
}
运行出的结果是 2 3 3 5,a b c d 都参与了运算的
|| 左边为真 右边不要算
#include<stdio.h>
int main()
{
int i=0,a=1,b=2,c=3,d=4;
i = a++ || ++b || d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
return 0;
}
结果是2 2 3 4 这里
如果a=0,,a++ || ++b || d++ 先使用a a是0; 0 || ++b 0为假 继续看++b ++b 等于3 3为真,所以后面的就不计算了 结果为1 3 3 4
条件操作符(三目操作符) if else ==(a>5 ? 1 : 2);
#include<stdio.h>
int main()
{
int a=3;
int b=0;
if(a>5)
{
b=1;
}
else
b=2;
printf("%d %d",a,b);
return 0;
#include<stdio.h>
int main()
{
int a=3;
int b=0;
b = (a>5 ? 1: 2);
printf("%d %d",a,b);
return 0;
}
这两个代码的结果是一样的,但是下面的那一个 b = (a>5? 1: 2)
解释:a大于5 吗?要是(if)a>5 b 的赋值就是1: 如果不的话(else)b的赋值就是2
逗号表达式:括号里的从左到右运算,但是最后的结果就是最后一个逗号后面的
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
int c = 0;
int d = (c = 5,a = c + 5,b = a - 4,c+=5);
printf("%d",d);
}
最后的结果应该等于5 因为从c = 5 开始,到c+=5结束,最后的 C 就是10了
如果是if语句的逗号表达式 if(a = b + 1,c = a / 2,d > 0) 判断是否进语句的是最后那个d > 0是否满足的条件 但是 这个 d 可能受到括号内前面的代码的影响
#include<stdio.h>
int main()
{
a = get_val;//有两块重复代码,会出现冗余现象
count_val(a);
while(a > 0)
{
a = get_val();
count_val(a);
}
}
#include<stdio.h>
int main()
{
int a;
while(a = get_val(),count_val(a),a > 0)
{
}
}
下标引用,函数调用和结构成员
1.下标引用操作符 [ ] 就是数组的[ ]
arr[ 有具体的某一个元素 ] 下标引用操作符
3 + 5 3和5是操作数,而这个的操作数是 arr ,4(就是arr和4)
操作数 :一个数组名 + 一个索引值
2、函数调用操作符
#include<stdio.h> //Add函数
int Add(int x, int y) //Add是函数名 x,y是函数参数(x,y也叫做传参) int是返回类型
{ //{}是函数体
int z=0;
z=x+y;
return z;
}//---------------------------------------
int main()
{
int a=10;
int b=20;
int sum = Add(a,b); //这里的( ),就是函数调用操作符
printf("%d",sum);
return 0;
}
操作数 : 函数名,+ 函数的参数 Add + a +b
3 . 结构成员的访问操作符
结构体:一组数据当中,有不同的数据类型,如 记录一个班级的学生的成绩,学生的名字是字符 ( char)类型,学生的成绩是浮点型(float)数据不同,不能用同一个数组来定义这一组 数据,所以引用了结构体 struct(也是一种数据类型) 来存放不同类型的一组数据,
一般结构为 struct 结构体{
成员列表 }
还是拿上面的班级举例子 结构体是 全班同学的成绩(class)成员列表是学生的名字 (name) 和学生的成绩(grade)
struct class
{ char name[ 40]
float grade[40] }
. 结构体 . 成员名
#include<stdio.h>
struct book
{
char name[20]; //书名
char id[20]; //编号
int price; //价格
};
int main()
{
struct book b = {"c语言","20221103",55};
printf("书名:%s",b.name);
printf("编号:%s",b.id);
printf("价格:%d",b.price);
return 0;
} //这里结果是初始值为无效定义,不知道为啥,等一会再解决
这里结果是初始值为无效定义,不知道为啥,等一会再解决 !!!!!!!!!!!!
晓得了,那个{ },打成( )
#include<stdio.h>
struct book
{
char name[20]; //书名
char id[20]; //编号
int price; //价格
};
int main()
{
struct book b = {"c语言","20221103",55};
*pb = &b; //结构体指针,指向的是b的内容
printf("书名:%s",(*pb).name);
printf("编号:%s",(*pb).id);
printf("价格:%d",(*pb).price);
return 0;
}
-> 结构体指针 ->成员名
#include<stdio.h>
struct book
{
char name[20]; //书名
char id[20]; //编号
int price; //价格
};
int main()
{
struct book b = {"c语言","20221103",55};
struct book *pb = &b; //结构体指针,指向的是b的内容
printf("书名:%s",pb->name);
printf("编号:%s",pb->id);
printf("价格:%d",pb->price);
return 0;
}
如果拿到的不是结构体变量而是结构体的指针,那么依然可以通过结构体的指针来找到结构体的成员