【C语言】操作符 精准讲解

本章介绍: \color{Red}本章介绍: 本章介绍:

  1. 各种操作符的全方位讲解。
  2. 表达式求值

操作符分类:

1 算术操作符

+      −      ∗      /      % \color{Red} + ~~ ~~-~~ ~~ * ~~ ~~ / ~~ ~~ \% +            /    %

  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  • 除法 / 得到的是商 \color{Red}除法 / 得到的是商 除法/得到的是商

  • 除法操作符的两个操作数都是整数的话,执行的是整数除法 。 用(%d打印)

  • 除法操作符的两个操作数只要有一个浮点数,执行的是小数除法。用(%lf打印)

  • $ 取模 % (取余)得到的是余数 \color{Red} 取模 \% (取余)得到的是余数 取模%(取余)得到的是余数

  • 取模操作符的操作数必须是整数


2 移位操作符

< < 左移操作符 \color{Red}<< 左移操作符 <<左移操作符
> > 左移操作符 \color{Red}>> 左移操作符 >>左移操作符
注:移位操作符的操作数只能是整数。

  • < < 左移操作符 \color{Red}<< 左移操作符 <<左移操作符
    1: 左移动操作符:左边丢弃,右边补0,(符号位也跟着丢)
    2: 每左移一位是乘2的效果

被左移时候的值是不变的,更动的赋值那个数
相当于 int a = -3; int b = a - 1;a的值是不跟着变化的在这里插入图片描述

  • > > 左移操作符 \color{Red}>> 左移操作符 >>左移操作符
    移位规则:
    每右移一位是除2的效果
    首先右移运算分两种:
  • 1. 逻辑移位 \color{Red}1. 逻辑移位 1.逻辑移位
    左边用0填充,右边丢弃
    1. 算书移位 \color{Red}1. 算书移位 1.算书移位
    左边用原该值的符号位填充,右边丢弃

移位图解:
在这里插入图片描述

  • 右移的时候,到底采用的是算术右移?还是逻辑右移,是取决于编译器的!
    在 V S 编译器里采用的是算术右移 \color{Green}在VS编译器里 采用的是算术右移 VS编译器里采用的是算术右移

(要用负数去测试)
如果逻辑右移,移动一位时候符号位变成0,是正数
如果算术左移,移动一位时候符号位变成1,是负数在这里插入图片描述

警告⚠: \color{red}警告⚠ : 警告
对于移位运算符,不要移动负数位,这个是标准未定义的。
例如:

int num = 10;
num>>-1; //error

3 位操作符

(位操作都是二进制位进行计算 ) \color{Goldenrod}(位操作都是二进制位进行计算) (位操作都是二进制位进行计算)
位操作符有:

&       按位与 \color{Red}\&~~~~ ~~按位与 &      按位与 ( 有0出0,全1出一)
∣         按位或 \color{Red}|~~~~~~~~按位或         按位或 ( 全0出0, 有1出1 )
  ˆ         按位异或 \color{Red}\^~~~~~~~~~按位异或  ˆ        按位异或 ( 相异出1, 相同出0)

注:他们的操作数必须是整数。

为了更好让大家理解,我还是以举二个例子的方式进行讲解~

  • 编写代码实现:求一个整数存储在内存中的二进制中 1 的个数 \color{Green}编写代码实现:求一个整数存储在内存中的二进制中1的个数 编写代码实现:求一个整数存储在内存中的二进制中1的个数

方法一:按位与 & \color{Red}\& &
按位循环1~32位,并分别与1按位与,因为&1时二进制只最低位是1,每次右移一次都会跟1比较( 有0出0,全1出一),当得到1的时候count++就可以得出二进制中有多少个1,代码如下:

整数在内存中存储的是: 补码(2进制)
15的二进制有4个10000000000000000000000001111
在这里插入图片描述

方法二:a&(a-1);

a&(a-1),第一时间肯定有点懵吧?不知道什么意思,我们举一个例子方便理解
![在这里插入图片描述](https://img-blog.csdnimg.cn/acc430cbc47842a4b37ac6c5eaaae417.png
)
每次 a & ( a − 1 ) 后 c o u n t + + \color{Magenta}每次 a \& (a - 1)后count++ 每次a&(a1)count++
每次 a & ( a − 1 ) 当 32 位都为 0 的时候,这个值就为 0 了,也就数完 a 中有几个 1 了 \color{Magenta}每次 a \& (a - 1)当 32 位都为 0 的时候,这个值就为0了,也就数完 a 中有几个 1 了 每次a&(a1)32位都为0的时候,这个值就为0了,也就数完a中有几个1
在这里插入图片描述

  • 不能创建临时变量(第三个变量),实现两个数的交换。 \color{Green}不能创建临时变量(第三个变量),实现两个数的交换。 不能创建临时变量(第三个变量),实现两个数的交换。
    在交换两个数的时,常常我们想到的方法是先创建一个临时变量,将一个变量放到临时变量里,然后把另一个变量放到第一个变量里,最后把第一个存起来的变量再放到另一个变量,但是这题限制了创造临时变量。
    方法一: \color{CornflowerBlue}方法一: 方法一:
    这可能是大多数人想出来的办法,先把a,b两个值加起来,存到a里面,然后把a-b存到b里面,最后再把a的值解去b的值,得到两个数的交换

这个代码存在一定的问题
如果a和b比较大,a和b相加会溢出!(因为int形的取值范围是-32768~32767)在这里插入图片描述

方法二: \color{CornflowerBlue}方法二: 方法二:
^ 按位异或

在这里插入图片描述
在这里插入图片描述
这样完美的解决了不能创建临时变量交换两个数的问题
但是这样的代码可读性不好,可能想半天都不知道干什么
所以在实际写代码时,还是创造两个临时变量来交换两个数
这里让大家更好的了解 ^的知识

4 赋值操作符

赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。

int weight = 120;//体重
weight = 89;//不满意就赋值

赋值操作符可以连续使用,比如:

int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值
这样的代码感觉怎么样?
那同样的语义,你看看:
x = y+1;
a = x;
这样的写法是不是更加清晰爽朗而且易于调试。
  • 复合赋值符: \color{red}复合赋值符: 复合赋值符:

+ = \color{red} += +=
− = \color{red}-= =
∗ = \color{red}*= =
/ = \color{red}/= /=
> > = \color{red}>>= >>=
< < = \color{red}<<= <<=
& = \color{red}\&= &=
∣ = \color{red}|= =
% = \color{red}\%= %=

这些运算符都可以写成复合的效果。
比如:

int x = 10;
x = x+10;
x += 10;复合赋值
其他运算符一样的道理。这样写更加简洁。

5 单目操作符

单目操作符介绍 \color{red} 单目操作符介绍 单目操作符介绍

!                    逻辑反操作 \color{red} ! ~~~~~~~~~~ ~~~~~~~~~ 逻辑反操作 !                   逻辑反操作
−                  负值 \color{red} - ~~~~~~~~~~~~~~~~~ 负值                  负值
+                  正值 \color{red} + ~~~~~~~~~~~~~~~ ~~ 正值 +                 正值
&                  取地址 \color{red}\& ~~~~~~~~~~~~~~~ ~~ 取地址 &                 取地址
s i z e o f          操作数的类型长度(以字节为单位) \color{red} sizeof ~~~~~~~~~操作数的类型长度(以字节为单位) sizeof         操作数的类型长度(以字节为单位)
− −             前置、后置 − − \color{red} -- ~~~~~~~~~~ ~~ 前置、后置--             前置、后置
+ +             前置、后置 + + \color{red} ++ ~~~~~~~ ~~~ ~~ 前置、后置++ ++            前置、后置++
∗                   间接访问操作符 ( 解引用操作符 ) \color{red} * ~~~~~~~~~~~~~~~ ~~~ 间接访问操作符(解引用操作符)                   间接访问操作符(解引用操作符)
( 类型 )          强制类型转换 \color{red} (类型) ~~~~~~~~~ 强制类型转换 (类型)         强制类型转换
~ 对一个数的二进制按位取反

  • ! 逻辑反操作 \color{Green} ! 逻辑反操作 !逻辑反操作

如果flag为真第一个if就进去判断条件
如果flag为假 !(逻辑反操作)让flag变成真 if进去判断条件在这里插入图片描述

  • & 地址 \color{Green}\&地址 &地址
  • ∗ 间接访问操作符 ( 解引用操作符 ) \color{Green} *间接访问操作符(解引用操作符) 间接访问操作符(解引用操作符)

这两个操作符跟指针又密切的关系,都是搭配使用的在这里插入图片描述

  • s i z e o f :操作数的类型长度(以字节为单位) \color{Green} sizeof:操作数的类型长度(以字节为单位) sizeof:操作数的类型长度(以字节为单位)

在这里插入图片描述

  • + + 前置、后置 + + \color{Green} ++前置、后置++ ++前置、后置++
  • − − 前置、后置 − − \color{Green} --前置、后置-- 前置、后置

- -前置:(先–,后使用) + +前置:(先+ +,后使用)
后置- -:(先使用,后–) 后置+ +:(先使用,后++)

总归前置是先++或者- -再使用
后置先使用再加减在这里插入图片描述

()强制类型转换 \color{Green} ()强制类型转换 ()强制类型转换
如果一个运算符两遍的运算数据类型不同,先要将其转换为相同的类型,强制类型转换可以消除程序中的警告,即确保写代码的程序员自己清楚类型转换,允许丢失一定精度,或做类型匹配

如果两个不同类型的数据进行一起运算,会报出程序警告这里是引用
强制类型转换就可以消除程序中的警告

  • ~ 对一个数的二进制按位取反
    把数据的每个二进制位取反,即把0变成1,把1变成0。

在这里插入图片描述


6 关系操作符

> \color{red} > >
> = \color{red} >= >=
< \color{red} < <
< = \color{red} <= <=
! =    用于测试“不相等” \color{red} !=~~~用于测试“不相等” !=   用于测试不相等
= =   用于测试“相等” \color{red} ==~~用于测试“相等” ==  用于测试相等

这些关系运算符比较简单,没什么可讲的,但是我们要注意一些运算符使用时候的陷阱。
警告: \color{red} 警告: 警告:
在编程的过程中 = = 和 = 不小心写错,导致的错误。 \color{Goldenrod}在编程的过程中== 和=不小心写错,导致的错误。 在编程的过程中===不小心写错,导致的错误。


7 逻辑操作符

& &   逻辑与 \color{red} \&\& ~ ~逻辑与 &&  逻辑与(都要是真的才可以执行)(并且)
∣ ∣       逻辑或 \color{red} || ~~~~~~ 逻辑或 ∣∣      逻辑或(只要一个为真就执行)(或者)

  • 区分逻辑与和按位与 \color{Green} 区分逻辑与和按位与 区分逻辑与和按位与

  • 区分逻辑或和按位或 \color{Green} 区分逻辑或和按位或 区分逻辑或和按位或
    (&&)(||):逻辑与和或 :只关注真假(非0就是真,0就是假)
    (&)(|) 按位与和按位或:二进制位进行计算

举例: \color{red} 举例: 举例:
1&2----->0
1&&2---->1
1|2----->3
1||2---->1

  • 为了更好理解逻辑与和逻辑或,习题方式进行讲解 \color{Green} 为了更好理解逻辑与和逻辑或,习题方式进行讲解 为了更好理解逻辑与和逻辑或,习题方式进行讲解
    以下代码输出的是什么
#include <stdio.h>
int main()
{
    int i = 0,a=0,b=2,c =3,d=4;
    i = a++ && ++b && d++;
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0;
}

解析: \color{red}解析: 解析:

答案是 a=1 b=2 c=3 d=4
&& 是控制求值顺序的,当运算 a++ 的时候,因为 a++ 是后置++(先使用后++),所以 a++ 这时还是 0,a为0,逻辑或有一个为假,表达式不成立,则后面的运算就不用再算了,相当于电路中的‘短路’.
这里是引用

如果把代码改成这样输出的又是什么

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++||++b||d++;
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}

解析: \color{red}解析: 解析:

a=1 b=3 c=3 d=4
||逻辑或(只要一个为真就执行)
||(逻辑或)它是只要遇到 (非0值)为真,表达式整体为真,后面表达式就不要再算了。当遇到 a++ 是后置++(先使用后++),所以 a++ 这时还是 0 ,到下一个 ++b 运算,b为2(非0为真)表达式整体为真 那就停下来了,所以 d++ 不运算,所以最后d的值是不变的。
这里是引用


8 条件操作符

  • e x p 1 ?     e x p 2 : e x p 3 \color{red} exp1 ? ~~~exp2 : exp3 exp1?   exp2:exp3

该条件操作符意思是
exp1为真时,exp2执行。
exp1为假时,exp3执行

  • 为了更好理解条件操作符,习题方式进行讲解 \color{green} 为了更好理解条件操作符,习题方式进行讲解 为了更好理解条件操作符,习题方式进行讲解

1:

if (a > 5)
        b = 3;
else
        b = -3;
转换成条件表达式,是什么样?

解析: \color{red} 解析: 解析:

第一种方法在这里插入图片描述
第二种
在这里插入图片描述

两种方法都可以使用,但是第一种方法更加简洁,阅读性更加好。 \color{green} 两种方法都可以使用,但是第一种方法更加简洁,阅读性更加好。 两种方法都可以使用,但是第一种方法更加简洁,阅读性更加好。

2:使用条件表达式实现找两个数中较大值。
该代码没什么好讲的,主要理解条件操作符就可以看懂了。

int main()
{	
int a = 10;
int b = 15;
int m = (a > b ? a : b);
printf("%d\n", m);
system("pause");
}

9 逗号表达式

e x p 1 , e x p 2 , e x p 3 , … e x p N \color{red}exp1, exp2, exp3, …expN exp1,exp2,exp3,expN

逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

  • 为了更好理解逗号表达式,习题方式进行讲解 \color{green} 为了更好理解逗号表达式,习题方式进行讲解 为了更好理解逗号表达式,习题方式进行讲解

1:

int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);逗号表达式
c是多少?

解析: \color{red}解析: 解析:

从左向右依次执行 a>b,这里只是判断,与c的值没关系
a=b+10 此时a的值已经变成了12
a=12
虽然最后一个表达式是结果:但是前面已经把a改成12,此时我们的a也应该是12
b=a+1 ==13
这里是引用


10 下标引用、函数调用和结构成员

1. [    ] 下标引用操作符 \color{red}1. [ ~~] 下标引用操作符 1.[  ]下标引用操作符
2. (   ) 函数调用操作符 \color{red}2. ( ~) 函数调用操作符 2.( )函数调用操作符
3. 访问一个结构的成员 \color{red}3. 访问一个结构的成员 3.访问一个结构的成员

  • 1. [    ] 下标引用操作符 \color{green}1. [ ~~] 下标引用操作符 1.[  ]下标引用操作符
    操作数:一个数组名 + 一个索引值
int arr[10];创建数组
 arr[9] = 10;实用下标引用操作符。
 [ ]的两个操作数是arr和9
  • 2. ( ) 函数调用操作符 \color{green}2. ( ) 函数调用操作符 2.()函数调用操作符
    接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
strlen("abcde")  ()函数调用操作符
"abcde"都是()的操作数
  • 3. 访问一个结构的成员 \color{green}3. 访问一个结构的成员 3.访问一个结构的成员

. 结构体 . 成员名 \color{Fuchsia} . 结构体.成员名 .结构体.成员名
− > 结构体指针 − > 成员名 \color{Fuchsia} -> 结构体指针->成员名 >结构体指针>成员名

. 结构体 . 成员名 \color{Fuchsia} . 结构体.成员名 .结构体.成员名

结构成员访问 . 操作符 结构体变量.结构体成员名在这里插入图片描述

− > 结构体指针 − > 成员名 \color{Fuchsia} -> 结构体指针->成员名 >结构体指针>成员名

我们得到的是一个指向该结构体的指针。这时候我们就需要操作符->
->是专门在访问结构体时使用指针的方法,更高效这里是引用


11 表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

11.1 隐式类型转换

C语言的整型算术运算总是至少以缺省整型(int)类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

整形提升针对的类型是小于整形的 比如char,short类型的运算时要送入CPU进行整型提升

char占用1字节空间,short占用2字节空间,在运算时都会提升为占用4个字节的int类型,运算完毕后然后在进行截断

  • 整型提升的意义: \color{green}整型提升的意义: 整型提升的意义:
  1. 表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
    一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

  2. 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。

  3. 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
    换为int或unsigne int,然后才能送入CPU去执行运算

例如:

//实例1
char a,b,c;
...
a = b + c;

b和c的值被提升为普通整型,然后再执行加法运算。
加法运算完成之后,结果将被截断,然后再存储于a中。

  • 如何进行整体提升呢? \color{green}如何进行整体提升呢? 如何进行整体提升呢?
    -整形提升是按照变量的数据类型的符号位来提升的

负数的整型提升:

char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111

正数的整形提升:

char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001

unsigned无符号整形提升:高位补0即可

  • 整形提升的例子 : \color{green}整形提升的例子: 整形提升的例子:
    实例 1 : \color{Orange}实例1: 实例1
int main()
{
	char a = 3;
	char b = 127;
	char c = a + b;
	printf("%d\n", c);
	return 0;
}

解析: \color{red}解析: 解析:

1:截断a,b

整型3的二进制补码是 0000000000000000000000000000011 \color{Orange} 0000000000000000000000000000011 0000000000000000000000000000011
把3存进char类型,但是char只能存储8个比特位(存的是最低8位) 所以发生截断成 00000011 \color{Orange} 00000011 00000011(存放整型3后面8个比特位)-

整型127的二进制补码是 0000000000000000000000000000000001111111 \color{Orange} 0000000000000000000000000000000001111111 0000000000000000000000000000000001111111
同样把他放进char类型,一样会截断成 01111111 \color{Orange} 01111111 01111111(存放整型127后面8个比特位)

2:a和b相加整型提升

ab在进行相加时候,a和b都是char类型的,达不到一个整型类型,所以这个地方要发生整型提升
char a 高位补充符号位,即为0符
0000000000000000000000000000011 \color{Orange}0000000000000000000000000000011 0000000000000000000000000000011

char b 高位补充符号位,即为0符
0000000000000000000000001111111 \color{Orange}0000000000000000000000001111111 0000000000000000000000001111111

3:截断c

a和b二进制相加为 00000000000000000000000010000010 \color{Orange}00000000000000000000000010000010 00000000000000000000000010000010 ,把他存储到c里,c也是个char类型,所以发生截断为 10000010 \color{Orange}10000010 10000010

4:%d整型打印-整形提升

printf(“%d\n”, c)中,%d是打印十进制的数,所以还需整形提升,这时c的二进制补码为10000010,符号位为1,整形提升高位补1,最终为 11111111111111111111111110000010 ( 补码 ) \color{Orange}11111111111111111111111110000010(补码) 11111111111111111111111110000010(补码) ,转换成原码为 10000000000000000000000001111110 \color{Orange}10000000000000000000000001111110 10000000000000000000000001111110
,最终这个数字输出为-126

实例 2 : \color{Orange}实例2: 实例2

int main()
{
 char a = 0xb6;
 short b = 0xb600;
 int c = 0xb6000000;
 if(a==0xb6)
 printf("a");
 if(b==0xb600)
 printf("b");
 if(c==0xb6000000)
 printf("c");
 return 0;
}

解析: \color{red}解析: 解析:

实例2中的a,b要进行整形提升,但是c不需要整形提升
a,b整形提升之后,提升后二进制序列就不同了,所以表达式 a0xb6 , b0xb600 的结果是假,但是c不发生整形提升,则表达式 c==0xb6000000 的结果是真. 打印c
在这里插入图片描述

实例 3 : \color{Orange}实例3: 实例3

int main()
{
 char c = 1;
 printf("%u\n", sizeof(c));
 printf("%u\n", sizeof(+c));
 printf("%u\n", sizeof(-c));
 return 0;
}

解析: \color{red}解析: 解析:

实例3中的,c只要参与表达式运算,就会发生整形提升
表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字节.
表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,
但是 sizeof© 没有参与任何运算,所以没有发生整型提升,,就是1个字节.
在这里插入图片描述
所以整型提升是真实存在的 \color{red}所以整型提升是真实存在的 所以整型提升是真实存在的

11.2 算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类
型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

l o n g    d o u b l e \color{Green}long ~~double long  double
d o u b l e \color{Green}double double
f l o a t \color{Green}float float
u n s i g n e d   l o n g   i n t \color{Green}unsigned~ long ~int unsigned long int
l o n g    i n t \color{Green}long ~~int long  int
u n s i g n e d   i n t \color{Green}unsigned ~int unsigned int
i n t \color{Green}int int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运
算。
警告: \color{red}警告: 警告:
但是算术转换要合理,要不然会有一些潜在的问题。
例如

float f = 3.14;
int num = f;  隐式转换,会有精度丢失

11.3 操作符的属性

复杂表达式的求值有三个影响的因素。

  1. 操作符的优先级
  2. 操作符的结合性
  3. 是否控制求值顺序。

两个相邻的操作符先执行哪个?**取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

优先级简单记就是: \color{Blue}优先级简单记就是: 优先级简单记就是: ! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

L-R是从左到右,R-L是从右到左,N/A是无结合性。

C 语言操作符优先级 \color{red}C语言操作符优先级 C语言操作符优先级

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 一些问题表达式 \color{red}一些问题表达式 一些问题表达式
    例 1 : \color{Goldenrod}例1: 1
表达式的求值部分由操作符的优先级决定。
表达式1
a*b + c*d + e*f

注释:代码1在计算的时候,由于*比+的优先级高,只能保证,的计算是比+早,但是优先级并不
能决定第三个
比第一个+早执行。
所以表达式的计算机顺序就可能是:

ab
c
d
ab + cd
ef
a
b + cd + ef
或者:
ab
c
d
ef
a
b + cd
a
b + cd + ef

例 2 : \color{Goldenrod}例2: 2

表达式2
c + --c;

注释:同上,操作符的优先级只能决定自减–的运算在+的运算的前面,但是我们并没有办法得
知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义
的。

例 3 : \color{Goldenrod}例3: 3

//代码3-非法表达式
int main()
{
 int i = 10;
 i = i-- - --i * ( i = -3 ) * i++ + ++i;
 printf("i = %d\n", i);
 return 0;
}

表达式3在不同编译器中测试结果:非法表达式程序的结果
在这里插入图片描述

例 4 : \color{Goldenrod}例4: 4

//代码4
int fun()
{
     static int count = 1;
     return ++count;
}
int main()
{
     int answer;
     answer = fun() - fun() * fun();
     printf( "%d\n", answer);//输出多少?
     return 0;
}

这个代码有没有实际的问题?
有问题!
虽然在大多数的编译器上求得结果都是相同的。
但是上述代码 answer = fun() - fun() * fun(); 中我们只能通过操作符的优先级得知:先算乘法,
再算减法。
函数的调用先后顺序无法通过操作符的优先级确定。

总结: \color{red}总结: 总结:
我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的$

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值