目录

# 运算符与表达式

## 什么是运算符

## 什么是表达式

## 运算符的分类

### 算术运算符

### 左值 和 右值

### 关系运算符

### 逻辑运算符

#### 例题:

### 位运算符

#### 按位取反 ~

##### 例题

#### 按位与 &

##### 例题

#### 按位或 |

#####例题:

#### 按位异或 ^

#####例题:

#### 按位右移

#### 按位左移

##### 例题:

### 赋值运算符 =

### 条件运算符 ? :

### 逗号表达式

### sizeof()求字节运算符

### 分量运算符

### 下标运算符

### 强制类型转换的运算符

### 其他运算符

## 总结

### 运算符的优先级和结合性

### 运算符优先级


# 运算符与表达式

C语言提供了所有你希望编程语言应该拥有的操作符,他甚至提供一些你意想不到的操作符。

事实上,C语言之所以被很多人认为它很难精通就是因为它品种繁多的操作符。

它的这个特点也是其他语言无法抗衡价值

## 什么是运算符

顾名思义,就是说运算符用来表示某种运算的符号

几目运算符?表示这个运算符要带几个操作数

单目运算符: 该运算符只需要一个操作数 eg:++ —

双目运算符: 该运算符只需要两个操作数 eg:+ – *

三目运算符: 该运算符只需要三个操作数 eg:a>b?a:b

结合性: 决定先算哪个操作数的问题

从左到右 还有 从右到左

eg:

a+b

b+a

在C语言中,含义是不一样的

+ 结合性: 从左到右

eg:

int i =5 , j = 6;

int a;

a = (i++) + (i+j); //17

int i =5 , j = 6;

int b;

b = (i+j) + (i++); //16

int i =5 , j = 6;

int a;

int b;

a = (i++) + (i+j); //17

b = (i+j) + (i++); //18

int i =5 , j = 6;

int a;

int b;

a = (++i) + (i+j); //18

b = (i+j) + (++i); //19

i++ ====> i = i+1

运算符的优先级:

在含有多个运算符的表达式中,决定先算哪个运算符,后算哪个运算符的问题

eg:

a+b*c

单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符

## 什么是表达式

表达式就是表达某个意思的式子

在C语言中,一般来说,表达式是指用运算符连接操作数的式子

3+5

eg:

sb250

i love you

520

合法的表达式就一定会有一个值,因为任何表达式都需要表达某个意思

## 运算符的分类

### 算术运算符

算术运算符:进行算术运算的运算符

++ — : 单目运算符

+ – * / % : 双目运算符

+ – * / : 只需要你的操作数是一个数(整数或者小数都可以)

% : 要求操作数必须是整数

++ — : 小数,浮点型

eg:

3+5 = 8

double + int ===》 double

3.0 + 5 = 8.0

int a,b;

a + b;

double f1 , f2;

f1+f2;

3.5 % 3 ==== error

% 表示取余

5/4 == 1

5.0 / 4 = 1.25

double / int===> double / double = double

(double)(3/2) = 1.0

(double)3/2 = 1.5

3/2.0 = 1.5

用C语言的表达式来表达数学表达式 a/b

(double) a/b

1.0*a / b

% 求余数

5 % 4 === 1

6 % 7 === 6

++(自增)运算符,单目运算符,要求操作必须是一个左值

–(自减)运算符,单目运算符,要求操作必须是一个左值

### 左值 和 右值

在这里介绍一下

为了理解一些操作数存在的限制,你必须要理解左边和右值之间区别。

左值就是赋符号(=)左边的东西,右值就是赋值符号右边的东西

eg:

a = b + 25;

a 就是 左值, b+25 就是右值

他们两个可以互换吗??

b + 25 = a;

原先用作左边的a此时变成了右值,因为每个位置它是不是肯定包含一个值,然后 b+25 不能作为一个左值,

因为它没有表示一个特定位置,因此,这个语句是非法!

注意当计算机去计算 b+25 的时候,它的结果必然保存在机器的某个位置,但是我们作为程序员没有办法来预测到这个位置在什么地方!

5++;errori++ === > i = i+1

(a+b)++;error

表达式的值 做完表达式后的值

i++ ii+1

++ii+1 i+1

i– ii-1

–ii-1i-1

### 关系运算符

这一类运算符用于测试操作数之间的各种关系的,c语言提供所有常见的关系运算符

不过,这一组操作符里面有一个大大的陷阱

这一组操作符:

> >= < <= != ==

前面四个操作符的功能你一看就知道是什么意思??

!= 操作符用来测试 ”不等于“

而== 操作符用于测试”等于“

关系表达式:用关系运算符连接起来的式子,如: a < b8 < 7

关系表达式的值:

关系成立 : 1

关系不成立 : 0

eg:

5 > 41

3 <= 4 1

5 > 7 0

3+5 < 7*8

(3+5) < (7*8)

8 1

5 > 4 > 3 这个东西是一个合法的关系表达式

1 > 3 —-> 0

在C语言中, 5>4>3 这个表达式和数学5>4>3的表达式不一样

(1)、在C语言中,5>4>3 ===》 1>3

(2)、数学上,5>4>3

5>3 并且 4>3

ps:

绝大部分其他的语言使用 = 操作符来进行比较 相等性 。在C语言中,你必须要用== 来进行比较,单个= 是赋值

这个的陷阱在于: 在测试相等性的时候出现赋值符号也是合法的!! 它不是一个语法错误

if(a==b)

if(a=b)

### 逻辑运算符

! 逻辑非单目运算符 ”取反“

&&逻辑与双目运算符”并且“ 从左到右

||逻辑或双目运算符”或者“ 从左到右

逻辑表达式:用逻辑运算符连接起来的式子,逻辑表达式

逻辑表达式的值:

逻辑为真: 1 (非0)

逻辑为假: 0

eg:

int a = 4 , b = 5;

a&&b; ===== 1

a||b; ===== 1

!a||b; ===== 1

!a&&b; ===== 0

5>3 && 8 < 4 – !0

5>3 && 8 < 3

1 && 0 =====> 0

ps. C语言运算符是”惰性运算“

(1)、a&&b&&c

只有当a为真的时候,才会去判断b

同时a和b都为真的时候,才会去判断c

(2)a||b||c

只要当a为真的时候,那么就不会再去判断b和c的值了

只有当a 为假的时候,才需要去判断b 的值

当b 为假的时候,才需要去判断c 的值

### 位运算符

位运算符是按bit为展开来进行运算,位运算符要求操作数必须是一个整数(兼容的整数),因为在进行位运算时,需要把操作数按bit展开。”按每一个bit位来进行操作的“

& 按位与

| 按位或

^ 按位异或

~ 按位取反

>> 按位右移

<< 按位左移

除了 ~ 是单目运算符之外,其他的位运算符全部是双目运算符,结合性是从左到右的,位运算的操作数只能是整型。所有的位运算都需要把操作数变成bit位序列,然后进行操作

#### 按位取反 ~

1 —》 0

0 —》 1

~3:

0000 0011

1111 1100

##### 例题

int a = ~(-3);

-3:

0000 0011

1111 1100

1111 1101

~0000 0010 ====>2

printf(“%d\n”,a); //2

printf(“%u\n”,a); //2

int a = !(-3)

printf(“%d\n”,a); //0

printf(“%u\n”,a); //0

!(非0) ==== 0

NOTE:

要注意 ~(按位取反) 和 !(逻辑非) 的区别

!(3+5) ==== 0

~ (3+5) ==== ~8

#### 按位与 &

a&b

aba&b

111

100

010

000

& 如果两个bit位都为1,结果才为1,否则为0

eg:

3 & 5

00000000000000000000000000000011

00000000000000000000000000000101

00000000000000000000000000000001 =====》1

3 & 7

00000000000000000000000000000011

00000000000000000000000000000111

00000000000000000000000000000011 ======》3

3&&5 ====》 1

5&&7 ====》1

NOTE:

注意&(按位与)与&&(逻辑与)的区别

ps.

一个bit位 与 0 进行按位与&操作,结果为0

X & 0 ==== 0

when x == 1 , 1&0 == 0

when x == 0 , 0&0 == 0

一个bit位 与 1 进行按位与&操作,结果保留原来的值

X & 1 == X

when x ==1 , 1 & 1 == 1;

when x ==0 , 0 & 1 == 0;

#### 按位或 |

a | b

aba|b

111

101

011

000

按位或,只要有一个bit操作数为1,结果就为1

3|5 === 7

00000000000000000000000000000011

00000000000000000000000000000101

00000000000000000000000000000111 ====》7

3||5 == 1

NOTE:

要区分 | 按位或 和 || 逻辑或的区别

一个bit位 与 1 进行 ”按位或|“的一个操作,结果为1

X | 1 ==== 1

一个bit位 与 0 进行 ”按位或|“的一个操作,结果保留原来的值

X | 0 ==== X

#### 按位异或 ^

“异或”:求异,不同为1 ,相同就为0

a ^ b

aba^b

110

101

011

000

eg:

3^5 === 6

00000000000000000000000000000011

00000000000000000000000000000101

00000000000000000000000000000110===>6

ps:

一个 bit 位 与 0 进行”按位异或 ^“,保留原值

x ^ 0 === x

一个 bit 位 与 1 进行”按位异或 ^“,结果相反

x ^ 1 === ~x

#### 按位右移

X >> N 把 x 按照bit位整体往右边移动n位!

低位右移后,舍弃

0000 1111 —-> xxxx 0000(右移四位)

高位补什么?? xxxx是什么??

对于无符号数,高位就全部补0

对于有符号数,高位就全部补原来的符号位

#### 按位左移

双目运算符,按bit位左移

2 < 40000 0010 ===> 0000 0100

高位左移,舍弃,低位就补0

如果左移动舍弃的高位是0,那么左移n位,表示的结果就乘以2的n次方

### 赋值运算符 =

双目运算符 , 结合性从右到左

x = y;

把表达式y的值,赋值给x(隐含了一个条件 x必须是一个可写的地址,具备左值,一般来说,X为一个可变的数据对象 ”变量“)

赋值表达式的左边(左操作数)必须为一个”可写的地址“ 左值

5 = 5; error

2 + 3 = 5; error

int i = 5;

i++ = 6; error

i = 6;

赋值表达式:是由赋值运算符连接起来的式子,赋值表达式

赋值表达式的值:就是你赋值后左边那个操作数的值

i = 5;

a = i = 5;

====>

a = (i = 5);

复合的赋值运算符 : 赋值运算符可以和算术运算符,位运算符复合的赋值运算符

+= -= *= /= %= >>= <<= != |= &= ^=

a+=b ====> a = a + b;

a >>= 2 ====> a = a >> 2;

a = a+b ; ===> a+=b;

### 条件运算符 ? :

三目运算符 结合性从右到左

experion ? a : b

上面这个是一个条件表达式

如果experion的值是为真,则整个条件表达式的值就为a

如果experion的值是为假,则整个条件表达式的值就为b

eg:

if(a>b)

{

a = 250;

}

else

{

a = 520;

}

a = (a>b) ? 250 :520

a = (a>b) ? (a = 250) : (a = 520)

### 逗号表达式

双目运算符,优先级就是最低的,结合性从左到右

表达式1 ,表达式2 ,表达式3 ……

逗号表达式的求值顺序:先求表达式1的值,再求表达式2的值,再求表达式3的值

整个逗号表达式的值就是表达式3的值

eg:

int a = 5 , b =6;

a = (a = 6 , a + b );

逗号表达式的扩展形式:

表达式1 , 表达式2 , 表达式3 ,…….,表达式n

求值顺序:

先求1,2,3,4,5,最后整个逗号表达式的值,是不是就是表达式n的值

### sizeof()求字节运算符

sizeof(类型); 求出这个类型的字节数

sizeof(typeof(1));

sizeof(typeof(1.0));

### 分量运算符

求结构体的成员变量 . ->

等后面结构体的专题再讲

### 下标运算符

int a[10];

a[0];

a[1];

a[2];

[]

…..

后面数组的时候也会涉及

### 强制类型转换的运算符

语法:(类型)值

eg:

(int)3.5 ===>3

typeof((int)3.5) ===> int

### 其他运算符

如:

函数调用符()

## 总结

### 运算符的优先级和结合性

= 不同于 ==

由Algol派生而来的大多数程序设计语言,例如:Ada,使用:== 作为赋值运算符,但是符号 = 作为比较运算符,而我们的C使用了另外一种表示方法,符号 = 作为赋值,== 作为比较!

一般来说,赋值运算符肯定是比 比较运算符,出现次数更加多,因此字符较少的 = 作为了赋值运算符

该语句的本意应该是检查x是否等于y

if(x = y)

{

break;

}

实际上将 y赋值给了x

&和| 不同于 && 和 ||

### 运算符优先级

我们需要记住两句话:

1、任何一个逻辑运算符的优先级低于任何一个关系运算符

2、移位运算符的优先级要比算术运算符要低,但是要比关系运算符要高