操作符分类
- 算数操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号操作符
- 下标引用、函数调用和结构成员
算术操作符
所有符号:+、-、*、/、%求余运算符
要注意的:
- /后不可为0;
- %左右必须是整数
- 当/两边有一个类型高于另一个,会隐式升级类型 // 比如有浮点型和整形,就会转换成浮点型的结果。
移位运算符
所有符号:>> 右移操作符、<<左移操作符
移位运算符顾名思义就是对二进制位进行移动操作。其中移位主要有两种移位方式。
1、逻辑移位
逻辑移位是指逻辑左移和逻辑右移,移出的空位都用0来补,移出去的抛弃。
2、算数移位
算术移位 就需要分有符号型值和无符号型值
对于无符号型值,算术移位等同于逻辑移位。
而对于有符号型值 ,算术左移等同于逻辑左移,算术右移补的是符号位,正数补0,负数补1。如下图所示
位操作符
所有符号:& //按位与
| //按位或
^ //按位异或
举几个简单的例子就能明白这三个操作符的意义
1、按位与& 0&0=0; 0&1=0; 1&0=0; 1&1=1
例子:11&6: 0000 1011 & 0000 0110 = 0000 0010 = 2
“与运算”的一些用途:
(1)清零。如果想将一个值清零,只需要令这个值与二进制位全为0(即0)的数进行与运算,那么得到的值就是0;
(2)取一个数的二进制序列中指定位的值
方法:首先确定要取位置,然后令和他与运算的数的位置为1,其他置为0。在进行与运算,得到的结果就是取我们需要的值。(看下面例子能更直观)
例:有一个数的二进制序列为1011 0110,
取X的高四位,用 这个数(即1011 0110) & 11110000= 10110000即可得到;
2、按位或| 0|0=0; 0|1=1; 1|0=1; 1|1=1
例子:11|6: 0000 1011 & 0000 0110 = 0000 1111= 15
即有真则为真
“或运算”的一些用途:
(1)常用来对一个数据的某些位置1。
方法:找到一个数X,对应X要置1的位,取该数的对应位为1,其余位为零。此数与之相或可使X中的某些位置1。
例:将X=10100000的低4位置1 ,用 X | 0000 1111 = 1010 1111即可得到。
3、按位异或^ 0^0=0; 0^1=1; 1^0=1; 1^1=0
例子:11|6: 0000 1011 ^* 0000 0110 = 0000 1101= 13
即不一样则为真,一样为假
“异或运算”的一些用途:
(1)1)使特定位翻转 找一个数。
方法:对应X要翻转的位,该数的对应位为1,其余位为零,此数与X对应位异或即可。
例:将X=10100001的低4位翻转 ,用 X ^ 0000 1111 = 1010 1110即可得到。
(2)与0相异或,保留原值 ,
例:X ^ 0000 0000 = 1010 0001。
(3)交换a和b
//不能创建临时变量(第三个变量),实现两个数的交换。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("a = %d b = %d\n", a, b);
return 0;
}
赋值操作符
符号:=
它的功能就是给一个变量赋值,他的优先级别低于其他的运算符,所以对该运算符往往最后读取。
**需要了解的:**复合赋值符
+= 、 -=、 *=、 /=、 %=、 >>=、 <<=、 &=、 |=、 ^=
复合运算符的目的是减少书写,更加简洁,举个例子
int x = 10;
x = x+10;
x += 10;//复合赋值
//其他运算符一样的道理。这样写更加简洁。
单目操作符
符号:
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
- - 前置、后置- -
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
用一个代码理解前面四个符号
int main()
{
int a = -10;
int *p = NULL;
printf("%d\n", !2);
printf("%d\n", !0);
a = -a;
p = &a;
printf("%d\n", a);
printf("%p\n", p);
return 0;
}
sizeof运算符:
作用:sizeof运算符能计算一个变量或者一个类型的字节长度
需要注意的:
1、sizeof是运算符不要和函数混淆;例如
#include<stdio.h>
int main()
{
int a=0;
printf("%d\n", sizeof a);//这样写行不行?
printf("%d\n", sizeof int);//这样写行不行?
return 0;
//第一种写法可以,但是第二种不行。
//第一种写法就说明sizeof不是函数,函数需要函数调用符()。
}
2、sizeof与数组
sizeof可以计算数组中元素数目的多少
方法:
sizeof(数组名)/sizeof(数组首元素)
前面会算出整个数组中\0前的字节长度,数组的字节长度等于数组元素类型字节长度乘数组元素个数,因此除数组首元素的长度就能得到数组元素个数(俗称数组长度)
需要注意,当我们向函数传递数组名,需要用到数组长度时,不能在函数内部算出此长度,必须将长度也传进函数。因为这时候的数组名代表的只是一个地址,并不代表整个数组。
++ - -运算符
运用方法
#include <stdio.h>
int main()
{
int a = 10;
int x = ++a;
//先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。
//x为11。
int y = --a;
//先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。
y为10;
a = 10;
x = a++;
//先对a先使用,再增加,这样x的值是10;之后a变成11;
y = a--;
//先对a先使用,再自减,这样y的值是11;之后a变成10;
return 0;
//这就是前置和后置的区别
}
* 间接访问操作符(解引用操作符)
用于对地址解引用,间接访问是相对于直接访问而言的,比如
int a = 1 ;
a = a + 1 ; //这就是直接访问a,因为用的是变量a本身
int b = 2 ;
int* p = &b ;
*p = 3 ; // 这就是间接访问,用指针p访问b。
(类型) 强制类型转换
其功能是把表达式的运算结果强制转换成类型说明符所表示的类型,举个例子来了解怎么用
int main()
{
float f=5.75;
printf("f=%d,f=%f\n",(int)f,f);
//运行结果 f=5,f=5.750000
}
关系操作符
所有符号:
>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”`
这些关系运算符比较简单,没什么可讲的,但是我们要注意一些运算符使用时候的陷阱。
警告: 在编程的过程中== 和=不小心写错,导致的错误
逻辑操作符
所有符号:
&& 逻辑与
|| 逻辑或
与运算,双目,对应数学中的“且”
或运算,双目,对应数学中的“或”
在编程中,我们一般将零值称为“假”,将非零值称为“真”。逻辑运算的结果也只有“真”和“假”,“真”对应的值为 1,“假”对应的值为 0。
注意:
1、区分逻辑与和按位与,区分逻辑或和按位或
1&2----->0
1&&2---->1
1|2----->3
1||2---->1
2、当进行与运算时,如果第一个表达式为假,则不会执行和判断第二个表达式,有假为假。
当进行或运算时,如果第一个表达式为真,则不会执行和判断第二个表达式,有真为真。
举个例子:
360面试题
#include <stdio.h>
int main()
{
int i = 0,
a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
} //程序输出的结果是什么?
条件操作符
符号:
条件? 表达式1 : 表达式2
条件运算操作会首先计算条件,然后根据条件的计算结果,再决定要计算两个表达式中的哪一个。
举个例子:找出两个数中的较大值
int iMax(int a, int b)
{
return a >= b ? a : b;
}
int iMAX2(int a,int b)
{
if (a > =b)
return a;
else
return b;
}//这两个函数实现的功能是一样的,但用条件操作符更加简单
逗号表达式
符号:
表达式1, 表达式2, 表达式3,......表达式N
它将两个及其以上的式子联接起来,从左往右逐个计算表达式,整个表达式的值为最后一个表达式的值。
举个例子:
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式 c是多少?
//代码2
if (a =b + 1, c=a / 2, d > 0)
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
//业务处理
}
下标引用、函数调用和结构成员
1.[ ] 下标引用操作符
操作数:一个数组名 + 一个索引值
int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
[ ]的两个操作数是arr和9
2.( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //实用()作为函数调用操作符。
test2("hello bit.");//实用()作为函数调用操作符。
return 0;
}
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;
}