目录
一.分类
二.操作符
1.算术操作符
2.移位操作符
(1).>>
(2).<<
(3).注意
(4).应用
3.位操作符
(1).使用
(2).应用
4.赋值操作符
5.单目操作符
(1).逻辑反操作
(1).sizeof与数组
(2).~
(3).++ --
(4).强制类型转换
6.关系操作符
7.逻辑操作符
8.条件操作符(三目操作符)
9.逗号表达式
10.下标引用操作符
11.函数调用操作符
12.结构成员
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
+ - * / %
1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
>> <<
进行移位操作的应该为整数的二进制补码
(1).算数右移:最右一位去除,符号位补为原符号位(通常)
(2).逻辑右移:最右一位去除,符号位补0
左边去除,右边补0
对于移位运算符,不要移动负数位,这个是标准未定义的。
num >> -1 //error
当我们要求一个数的二进制表示中1的个数,我们可以使用移位操作符和位操作符(就在下面有讲)
想要统计二级制中1的个数,我们可以用各位的1来与这个数按位与来判断该位是否为1
而想要的到每一位的1,我们可以利用循环和移位
整体代码如下所示
#include
int main()
{
int num = -1;
int i = 0;
int count = 0;
for(i=0; i<32; i++)
{
if( num & (1 << i) )
count++;
}
printf("二进制中1的个数 = %d\n",count);
return 0;
}
进行操作的也是二进制补码
&按位与 两个数的相应位均为1时结果位为1
| 按位或 两个数的相应位均为0时结果位为0
^按位异或 两个数的相应位相同时结果位为0,相异为1
例如 int a=5,b=3;
将两个数转化为二进制
a:00000000 00000000 00000000 00000101
b:00000000 00000000 00000000 00000011
若c=a&b
c:00000000 00000000 00000000 00000001
当我们要进行两个数的交换时,我们首先会想到创建临时变量来解决
那么如何不使用临时变量来解决这个问题?
我们首先可以想到使用加减法来解决
a=a+b;
b=a-b;
a=a-b;
这的确是一种思路,然而当a+b的结果超出a,b的取值范围时,这种方法便会出现问题
我们还可以使用位操作符来解决这个问题
a=a^b;
b=a^b;
a=a^b;
(1).当a=a^b时,a的二进制中的1表示两数该位原本不同,0表示相同
例如a=5,b=3
转换为二进制为
a:00000000 00000000 00000000 00000101
b:00000000 00000000 00000000 00000011
a=a^b后
a:00000000 00000000 00000000 00000110
(2).当b=a^b时
b:00000000 00000000 00000000 00000101
可以看到,b已经等于原本a的值
(3).当a=a^b时
a:00000000 00000000 00000000 00000011
如此,便完成了a与b的交换
而这种办法,由于按位异或是对二进制进行操作,所以不会发生超出范围的问题
(1).=
(2).赋值操作符可以连续使用
(3).复合赋值符
+= -= *= /= %= >>= <<= &= |= ^=
! 逻辑反操作
- 负值
+ 正值(可以忽略)
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
这些单目操作符,其实有很多我们经常使用到,例如 - + & *,这里就不做赘述。
在if(flag)中,判断条件为flag为真
当为if(!flag)时,判断条件为flag为假
布尔类型
布尔类型就是用来表示真假的类型
stdbool.h
_Bool(bool) flag=true(false)
自定义函数的返回值也可以为布尔类型,但注意返回值只能为true/false
(1).若操作数为表达式,不进行实际运算
(2).sizeof后的括号可以省略
(3).
#include
void test1(int arr[])
{
printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));
}
int main()
{
int arr[10] = {0};
char ch[10] = {0};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(ch));
test1(arr);
test2(ch);
return 0;
}
以上代码所打印的应为40 10 4 4
由于int类型数据占4个字节,char类型数据占1个字节,所以前两个为40,10,这很好理解
而当传参后,sizeof的操作数arr ch都变为了指针类型,所以在x64中都为4
按位取反(包括符号位)
(1).前置先运算再赋值,后置先赋值再运算
(2).++ --不要乱用,例如b=a++会对a做出改变,而b=a+1不会
(3).指针也可以使用
尽量避免强制类型转换
> >= < <= != ==
&& 逻辑与
|| 逻辑或
在if语句中我们已经使用过这两个操作符
1.&&——两侧都为真时返回1,否则返回0
从左向右判断,左侧为假,右侧不进行运算
2.||——两侧都为假时返回0,否则返回1
从左向右判断,左侧为真,右侧不进行运算
exp1 ? exp2 : exp3
当exp1成立时执行exp2,否则执行exp3
例如
b=(a>5 ? 3 : -3);
等同于
if(a>5)
{
b=3;
}
else
{
b=-3;
}
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
例如
int a=1;
int b=2;
int c=(a>b , a=b+10 , a , b=a+1);
//a=12 b=13 c=13
在了解到逗号表达式后,我们可以对一些代码进行优化
a = get_ _va1();
count_ va1(a);
while (a > 0)
{
//业务处理
a = get_ _va1();
count_ val(a) ;
}
如果使用逗号表达式,改写:
while (a = get_ _va1(), count_ val(a),a>0)
{
//业务处理
}
但一定要思考清楚使用逗号表达式是否恰当
[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值
例如int arr[10]={ 0 }
那么 arr[9] 中 arr 和 9 便是操作数。
( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
当函数没有参数时,该操作符的操作数最少,为1。
(1).内置类型——char、int.....
自定义类型(聚合类型)——结构体、枚举、联合体
(2).结构体
在描述某些对象时,不能简单地使用单个内置类型,可以选择结构体来进行描述
以一本书为例,要有名字、价格等
struct Book//类型
{
char name[10];
int price;
};
int main()
{
struct Book b1={"书名",10};
return 0;
}
而当我们要使用结构体中的结构成员时,有以下两种方法
. 结构体.成员名
-> 结构体指针->成员名
例如我们要打印结构成员时
printf("%d\n",b1.price)
而和其他数据一样,当进行传参时,传值操作也会导致无法改变原数据
所以要使用结构体指针
void print1(struct Book* p)
{
printf("%s %s %d\n", (*p).name, (*p). author, (*p). price);
printf("%s %s %d\n",p->name, p->author, p->price);
}
我们可以采用常规的解引用操作符,也可以使用我们上面说到的->操作符
表达式求值
累了,不写了,下一篇再说