+ - * / %
1.对于 / 操作符,如果两个操作数都是整数,执行整数除法;只要有一边是浮点数就是浮点数的除法。
2.操作符 % 为取余,两边的数必须都是整数,不能为浮点数。剩下的几个操作符都可以作用于整数和浮点数。
<< 左移操作符
>> 右移操作符
1.操作数只能是整数
2.移动的是二进制
计算机中都是由二进制表示信息的,整数二进制有三种表示形式:原码、反码、补码
1.正整数的原码、反码、补码都是相同的
2.负整数的原码、反码、补码需要计算
1.无论该整数是正的还是负的都可以写出原码:根据正负直接写出的二进制序列就是原码。
2.十进制到二进制的转化方法:除2取余,逆序排列。
假如我们这里给个 int a = 15,15的二进制是1111,一个整型占4个字节,也就是32位,所以前28位都是0。二进制第一位是符号位,0为正,1为负。
int a = 15;
// 0000 0000 0000 0000 0000 0000 0000 1111 原码
// 0000 0000 0000 0000 0000 0000 0000 1111 反码
// 0000 0000 0000 0000 0000 0000 0000 1111 补码
int a = -15;
// 1000 0000 0000 0000 0000 0000 0000 1111 原码
// 1111 1111 1111 1111 1111 1111 1111 0000 反码(符号位不变,按位取反)
// 1111 1111 1111 1111 1111 1111 1111 0001 补码(按位取反,末位加1(反码加1)/从右往左遇见的第一个1不变,前面按位取反)
整数在计算机内存中存储的是补码,计算的时候使用补码计算。
所以移位移动的是二进制序列的补码
#include<stdio.h>
int main()
{
int a = 15;
int b = a >> 1; //右移
printf("%d\n", b);
return 0;
}
右移运算分为两种:逻辑右移(右边丢弃,左边补0);算术右移(右边丢弃,左边补符号位)
左边丢弃,右边补0
不要移动负数位,标准未定义
与移位操作符一样都是操作二进制
位操作符的操作数必须是整数
对应二进制位有0则0,全1为1
#include<stdio.h>
int main()
{
int a = 3;
// 0000 0000 0000 0000 0000 0000 0000 0011 原码
// 0000 0000 0000 0000 0000 0000 0000 0011 补码
int b = -5;
// 1000 0000 0000 0000 0000 0000 0000 0101 原码
// 1111 1111 1111 1111 1111 1111 1111 1011 补码
printf("%d\n", a & b); // 有0则0,全1为1
// 0000 0000 0000 0000 0000 0000 0000 0011
// 1111 1111 1111 1111 1111 1111 1111 1011
// 0000 0000 0000 0000 0000 0000 0000 0011 结果 3
return 0;
}
对应二进制位有1则1,全0为0
#include<stdio.h>
int main()
{
int a = 3;
// 0000 0000 0000 0000 0000 0000 0000 0011 原码
// 0000 0000 0000 0000 0000 0000 0000 0011 补码
int b = -5;
// 1000 0000 0000 0000 0000 0000 0000 0101 原码
// 1111 1111 1111 1111 1111 1111 1111 1011 补码
printf("%d\n", a | b); // 有1则1,全0为0
// 0000 0000 0000 0000 0000 0000 0000 0011
// 1111 1111 1111 1111 1111 1111 1111 1011
// 1111 1111 1111 1111 1111 1111 1111 1011 补码
// 1000 0000 0000 0000 0000 0000 0000 0101 -5
return 0;
}
对应的二进制位不同为1,相同为0
#include<stdio.h>
int main()
{
int a = 3;
// 0000 0000 0000 0000 0000 0000 0000 0011 原码
// 0000 0000 0000 0000 0000 0000 0000 0011 补码
int b = -5;
// 1000 0000 0000 0000 0000 0000 0000 0101 原码
// 1111 1111 1111 1111 1111 1111 1111 1011 补码
printf("%d\n", a ^ b); //不同为1,相同为0
// 0000 0000 0000 0000 0000 0000 0000 0011
// 1111 1111 1111 1111 1111 1111 1111 1011
// 1111 1111 1111 1111 1111 1111 1111 1000 补码
// 1000 0000 0000 0000 0000 0000 0000 1000 -8
return 0;
}
不使用中间变量,实现两个数的交换(按位异或)
#include <stdio.h>
int main()
{
int a = 3;
int b = 5;
/*
常规做法
int tmp = a;
a = b;
b = tmp;
*/
//不允许使用中间变量
/*
a = a + b; //把和放到a中
b = a - b; //b为和减去b
a = a - b; //a为和减去b
缺陷:a和b很大,二者的和会超过int的范围
*/
a = a ^ b;
b = a ^ b;
a = a ^ b;
// a^a 0
// a^0 a
// a = 3;
// b = 5;
// a^b^a ?
// a 0011
// b 0101
// a^b 0110
// a^b^a 0110 0011 —— 0101 —— b
// a^a^b a^a=0 0^b=b
// a^b^a = a^a^b ,交换律
printf("%d %d\n", a, b);
return 0;
}
赋值操作符中除了**=**外,还有很多个复合赋值操作符, +=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=
单目操作符的操作数只有一个
可以理解为把真的变成假的,把假的变成真的
#include<stdio.h>
int main()
{
int x = 0;
if (x == 0)
printf("hello\n");
if (!x)
printf("world\n");
if (x)
printf("!\n");
return 0;
}
在上述代码中,有三个条件语句,第一个当x为0,输出hello;第二个0为假,非0为真,所以 !x为真,输出world;第三个0为假,非0为真,所以x为假,不输出 !
这里的 +, -,是正值和负值的意思,并不是加和减的意思,-1的负号就是单目操作符,它的操作数只有一个;2-1的减号是双目操作符,它的操作数有两个,分别是2和1。
& 为取地址, * 不是乘的意思,它是间接访问操作符,也称作解引用操作符,两者通常应用于指针。
#include<stdio.h>
int main()
{
int a = 1;
int* pa = &a;
//&a将a的地址取出来,放到pa变量中,类型是int *
*pa = 2; //间接访问操作符,通过pa中存放的地址找到指向的内容或者空间
int b = *pa;
return 0;
}
sizeof是操作符,不是函数。它可以求变量或者类型所占空间的大小,单位是字节。
#include<stdio.h>
int main()
{
int a = 1;
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
//printf("%d\n", sizeof int);错误写法
return 0;
}
除此之外,sizeof还可以计算数组的大小,单位同样是字节。
#include<stdio.h>
int main()
{
int arr[10] = {0};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(int [10])); //[]中的数字不能去掉
//printf("%d\n", sizeof(int [])); 错误写法
return 0;
}
按位取反是对二进制进行取反。
#include<stdio.h>
int main()
{
int a = 0;
printf("%d\n", ~a);
//0的补码是 0000 0000 0000 0000 0000 0000 0000 0000
//对0的补码取反为 1111 1111 1111 1111 1111 1111 1111 1111
//取反后的原码为 1000 0000 0000 0000 0000 0000 0000 0001
//所以结果是-1
return 0;
}
下面这段代码,问题分析都在注释中写出来了
#include<stdio.h>
int main()
{
int a = 13;
//方便起见,只写八位
//13是 0000 1101
//要得到 0001 1101 真值为29
//按位或是有1则1
//可以将13与 0001 0000按位或
//0001 0000是0000 0001左移4位得到,也就是将1左移4位,将a按位或0001 0000即可
a |= (1 << 4);
printf("%d\n", a);
//通过0001 1101 真值为29
//得到0000 1101 真值为13
//按位与是全1才1
//将0001 1101 按位与 1110 1111,即对0001 0000按位取反,也就是将1左移4位,取反。按位与。
a &= (~(1 << 4)); //不知道优先级的话可以都带上括号
printf("%d\n", a);
return 0;
}
感兴趣可以琢磨琢磨下面的代码
#include<stdio.h>
int main()
{
int a = 0;
//第一种写法
//while (scanf("%d", &a) == 1)
//{
// printf("%d\n", a);
//}
//第二种写法
//while (scanf("%d", &a) != EOF)
//{
// printf("%d\n", a);
//}
//第三种写法
while (~scanf("%d", &a))
{
printf("%d\n", a);
}
return 0;
}
++ 和 - - 分别都有前置和后置两种,前置为先运算后使用,后置为先使用后运算
> >= < <= != ==
注意:== 和 =的区别
&& 逻辑与(并且)
|| 逻辑或(或者)
语句1 ? 语句2 : 语句3
类似于
if (语句1)
语句2;
else 语句3;
C语言中唯一的三目操作符
语句1,语句2,语句3,语句n
从左向右计算,整个表达式的结果是最后一个表达式的值
1.下标引用操作符 []
操作数:数组名 + 索引值
2.函数调用操作符 ()
第一个操作数是函数名,剩余操作数是传递给函数的参数。
最少有一个操作数
3.访问结构成员 . 结构体.成员名
-> 结构体指针->成员名
#include <stdio.h>
struct Stu
{
char name[10];
int age;
char sex[5];
double score;
};
void set_age1(struct Stu stu)
{
stu.age = 18;
};
void set_age2(struct Stu* pStu)
{
pStu->age = 18;//结构成员访问
}
int main()
{
struct Stu stu;
struct Stu* pStu = &stu;//结构成员访问
stu.age = 20;//结构成员访问
set_age1(stu);
pStu->age = 20;//结构成员访问
set_age2(pStu);
return 0;
}