详细介绍了C语言表达式、算术运算符、赋值运算符、关系运算符、条件结构、逻辑运算符、位运算符的语法和使用方法,并讨论了运算符的优先级。
1、表达式与算术运算符
在C语言中,表达式是一个类似数学中的算式,表达式由变量、字面值、常量、运算符号构成。表达式的计算结果是一个值,值的类型可以数值,也可以是逻辑值。
【 例3-1 】 计算存款一年本金利息和的表达式
deposit*(1+rate)
在上面的表达式中,deposit是存储存款额度的变量,rate是存储银行年利率的变量,数字1是字面值,符号“*”是乘法运算符,表达式中的括号和数学四则运算的括号意义相同,用于提高括号内子表达式的运算优先级。
观察发现,1+rate也是一个表达式,它符合表达式的定义,在当前表达式中,该表达式为子表达式,因此一个复杂的表达式由多个子表达式构成。
在C语言中,表达式中的运算符号称为运算符,运算符作用的变量、常量、字面值、子表达式称为操作数。例如:运算符号“*”两边的操作数为变量deposit和子表达式(1+rate);运算符号“+”两边的操作数为字面值1和变量rate。
运算符若需要N个操作数参与运算,则称为N目运算符。例如:加法、乘法、除法等运算符都需要两个操作数参与运算,称为双目运算符;自增、自减运算符需要单个操作数参与运算,称为单目运算符。
表达式左侧一般是待赋值的变量,该表达式返回的结果为浮点类型,计算结果赋值给表达式左侧的变量。
例如:
total = deposit*(1+rate)
表达式的计算结果赋值给变量total。
【 例3-1 】表达式的运算符在运算类型属于算术运算符,其作用和数学中的运算符相同,下表列出了C语言支持的算术运算符。
表中的加、减、乘、除运算符比较容易理解和掌握,下面重点介绍取余、自增、自减运算符。
取余运算符
取余运算符是双目运算符,需要两个操作数。可以用来计算两个数之间的余数,它可以用在整数和浮点数之间,但是最终结果只能是整数。运算结果是运算符左边的操作数除以运算符右边的操作数后所得的余数。
假设 a % b =c(余数为d),其中a和b均为整数,则余数d为a % b的结果。
取余运算符可以解决一些简单的数学问题。例如:可以使用取余运算符来检查一个数是否为偶数,如果一个数除以2的余数是0,那么它就是偶数;也可以用来检查一个数是否是3的倍数,如果一个数除以3的余数是0,那么它就是3的倍数。
自增自减运算符
自增自减是单目运算符,只需要一个操作数参加运算。自增和自减从字面上理解就是自身增加或减少,增加或减少多少呢?自增是自身做加1操作,自减是自身做减1操作。在c语言中,并不是所有变量都可以使用自增自减操作符;可以使用自增自减操作符的数据类型有:int、float、double 、char、long。
自增(++):将变量的值加1,分前缀式(如++a)和后缀式(如a++)。前缀式是先加1再使用;后缀式是先使用再加1。
例如:
int count=10;
printf("count=%d",count++);
上述程序段执行后,输出结果是10还是11呢?count++是后缀式,后缀式是先使用再加1,因此先输出count的当前数值,然后count再做加1操作,输出结果是10。
int count=10;
printf("count=%d",++count);
上述程序段执行后,输出结果是11。因为++count是前缀式,前缀式是变量先自增再使用,变量count先做加1操作,然后再输出变量count的值。
自减(--):将变量的值减1,也分前缀式(如--a)和后缀式(如a--)。前缀式是先减1再使用;后缀式是先使用再减1。
2、赋值运算符
我们回顾一下数学运算符号“=”,在数学中该符号是表示相等的符号,读作“等于”。等号表示两端的数字、算式是相等的。如:2+3=5,就是表示等号左边的2加上3与右边的5是相等的,7-2=2+3表示左右两边算式相等。
在C语言中,也用到了符号“=”,不过和数学中的等号意义完全不同,C语言中的“=”是赋值的意思,该符号是赋值运算符,它是一个双目运算符,它的作用是将右侧的值赋值给左侧的变量。
例如:
int a,b;a = 30;b = a+20;
上述代码执行后,a的值为30,b的值为50。赋值运算符“=”左侧的操作数必须是变量,右侧的操作数可以字面值、变量、常量或表达式,若赋值运算符右边的操作数为表达式,编译器会先计算表达式的值,然后再将值赋值给运算符左侧的变量。
可以在声明变量时为变量赋值:
int a=30,b=a+20;
上面的语句在定义变量b时用到了变量a,因为变量a在变量b之前已被定义,因此上面的语句是合法的。
为了简化计算,C语言还提供了复合赋值运算符,复合赋值运算符是赋值运算符和算术运算符合并成一个新的运算符,该运算符称为复合赋值运算符。使用复合赋值运算符时,被赋值的变量首先使用算术运算符与右侧的数值或算术表达式进行运算,然后将运算结果再赋值给变量。
赋值运算符可以和所有的算术运算符结合构成复合赋值运算符,运算效果等同于上图的“+=”复合赋值运算符。表3-2列出了“+=、-=、*=、/=、%=”复合赋值运算符的描述及例子。
在复合赋值运算符表格中,“例子”一栏中a是变量。运算顺序是先执行算术运算,然后再执行赋值运算。运算符右侧的操作数可以是数值、也可以是算术表达式,算术表达式的运算顺序同数学运算顺序一致。
下面给出复合赋值运算符“+=”的解释说明,其它复合赋值运算符的运算过程基本相同。
复合赋值运算符“+=”,表示的意思是先将运算符左边操作数指向的变量值和右边的操作数执行相加操作,然后再将相加的结果赋值给左边的操作数指向的变量。例如下面语句:
int a = 10;
a += 20;
此时,变量a等于30,其过程是变量a先与数值20相加,因为变量a的值是10,因此与数值20相加的结果是30,再将30赋值给变量a,此时变量a的值为30。
3、关系运算符
人们在网上挑选商品时,一般会使用电商的商品价格排序功能,将商品按照价格从低到高排列,然后再看商品的评论多少和评论内容来筛选商品,这样就会大概率买到质优价廉的商品。
电商的商品价格排序功能的核心就是比较商品间的价格高低,也就是比较多个数值的大小,并对数值按从小到大或从大到小排序。
比较两个数值的大小,也就是要弄清两个数之间的大小关系。两个数之间的大小主要存在六种关系,分别是大于关系、大于等于关系、小于关系、小于等于关系、等于关系、不等于关系。例如,对于35和26两个数来说:35大于26就是大于关系;26小于35就是小于关系。
用于比较两个数大小的运算符称为关系运算符,关系运算符是双目运算符,用在关系表达式中。用于判断两个数据之间的关系,例如:大于、等于、不等于,比较的结果是一个整型数值1或 0,1表示“真”,0表示“假”。当条件成立时,运算结果为1;当条件不成立时,运算结果为0。下表列出了C语言支持的比较运算符,表中例子假设A和B不相等且A小于B。
表3-3的A和B是两个整数类型的变量,且A小于B。运算符“==”检查A和B的值是否相等,因为A和B不相等,因此关系表达A==B返回0(假),关系表达式A!=B则返回1(真)。
4、条件结构
我们通过一个编程案例来引入条件结构。
编程案例:要求用户输入两个不相等的整数,如果这两个数的和大于100,则显示“两数和大于100”,否则显示“两数和小于等于100”
应用我们前面学过的C语言知识,类似这样的编程要求很难实现,因为程序需求涉及到了条件判断,并根据条件判断结果选择不同的执行分支。在生活中,也常常会遇到许多需要判断的情况,在这种情况下,需要根据一些条件作出决定和选择。例如,在我们打算出门时,需要判断天气怎么样,如果下雨了,就要带上雨伞;外出旅行时,需要根据不同情况,选择不同的交通工具。
下面我们来学习一种新的程序结构——条件结构。
前面编写的程序都是“顺序流程”,每条语句顺序执行。但是在很多情况下,程序并不是按既定的顺序执行,而是根据不同请况进行判断,然后执行不同的操作,这种流程称为“条件分支流程”,其结构也称为“条件结构”。
条件结构的核心是条件判断,在C语言中,条件判断可以使用关系表达来实现,关系表达式的计算结果返回逻辑真或逻辑假,在C语言中非0数值表示逻辑真,数值0表示逻辑假。若关系表达式返回逻辑真,则执行分支语句块A,否则执行分支语句块B,这里的分支语句块A和分支语句块B是不同的执行语句块,在条件结构中,A语句块和B语句块永远不能同时执行。
在C语言中,提供了if-else语法结构来实现条件结构。
其中if和else是C语言的关键字,<条件>是一个关系表达式、变量或字面值。变量或字面值的类型应为整数、浮点类型。C语言规定非0的数值为逻辑真,数值0为逻辑假。<条件>执行后,若返回逻辑真执行<分支语句块A>,否则执行<分支语句块B>。
在一些情况下,可能只需要执行满足条件的<分支语句块A>,而不需要执行不满足条件的<分支语句块B>,在这种情况下,就可以把else和<分支语句块B>省略掉。
现在,我们已经了解了C语言的条件结构和语法,下面探讨一下如何在条件结构中使用关系表达式。
例如:要测试两个整数类型的变量值num1和num2是否相等,可以编写num1 == num2,然后将其放入一个条件结构中,如下所示:
if ( num1==num2 )
{
……
}
else
{
……
}
如果num1和num2的数值相等,则条件为真,执行if后面的语句块,否则条件为假,执行else后面的语句块。
下面我们来实现前面的程序需求,编写程序前,先绘制程序流程图。
在程序流程图中,条件结构使用菱形图形符号表示,该图形符号有一个输入和两个输出分支,分别对应条件判断的逻辑真和逻辑假。
程序清单
#include
void main()
{
int x,y;
// 提示用户输入两个整数
printf("请输入两个整数数:n");
// 获取用户的输入
scanf("%d",&x);
scanf("%d",&y);
// 条件结构
if ((x+y) > 100)
printf("x+y >100");
else
printf("x+y<=100");
}
5、逻辑运算符
在数学中,表示一个数值的范围时,经常用不等式来表述。例如:假设一个数值取值范围为0到100,设该数值为x,不等式0
例如:要判断学生的考试成绩是否在90至100范围内,就需要使用逻辑运算符连接两个关系表达式来完成条件判断。
下表列出了C语言支持的逻辑运算符,表中假设整型变量A为真(数值为1),整型变量B为假(数值为0)。
假如考试成绩用变量score表示,下面的语句可以判断score是否在90至100范围内。
score >=90 && score <=100
当score的值在90至100范围内时,上面语句的运算结果为逻辑真(1)。因为运算符“&&”两边的关系表达式的运算结果都为逻辑真(1);当score的值不在90至100范围内时,上面语句的运算结果为逻辑假(0)。因为运算符“&&”两边的关系表达式的运算结果都为逻辑假(0),或有一个关系表达式的运算结果为逻辑假(0)。
例如下面的代码段执行完成后,bJudge的值是1还是0呢?
int a = 10;
int b = 20;
int c = 15;
int bJudge = c > a && c < b;
上述代码段的最后一条语句同时出现了赋值运算符、关系运算符和逻辑运算符,C编译器会先执行哪个运算操作呢?同数学的四则运算一样,运算符也有优先级,运算顺序由高优先级到低优先级下表列出了运算符的优先级。表中优先级栏,数字越小优先级越高,运算符每个运算符用中文顿号分割。
表中小括号‘()’优先级最高,表达式含有小括号的,优先执行小括号的内容,如果包含多个小括号,执行顺序是从左到右。
例如,假设变量a的值为12,下述语句的执行会有不同的结果:
(1)执行 a + 18 % 4 ,因为运算符%的优先级高于运算符+,该语句先执行取余运算,再执行加法运算,其结果为14;
(2)执行( a + 18 ) % 4 ,因为小括号的优先级最高,该语句先执行小括号里的表达式a+18,再执行取余运算,其结果为2;
(3)执行 a * ( ( a + 18 ) % 4 ),该语句括号内嵌套括号,执行顺序是先执行内层括号的运算,再执行外层括号的运算,其运算结果为24。
了解了运算符的优先级,现在可以确定下述语句:
int bJudge = c > a && c < b;
bJudge的值为数值1(逻辑真)。
逻辑与运算符“&&”连接了2个关系表达式,分别是c > a和c < b,如果这两个表达式计算结果都为真,则bJudge为1(真),否则bJudge为0(假)。此时bJudge的值为1(真)。该运算符还有一个特点,当左侧的关系表达式或变量为0(假)时,则直接返回结果0(假),不再执行运算符右侧的表达式。
逻辑或运算符“||”,用于判断运算符两边的条件表达式或整型变量是否有一个为真,如果有一个为真,返回结果为1(真),否则返回0(假)。
逻辑非运算符“!”,用于判断运算符两边的条件表达式或整型变量是否有一个为1(真),如果有一个为1(真),返回结果为1(真),否则返回0(假)。
6、位运算
位运算在嵌入式开发编程中是常用的一种运算,单片机的控制方式都是通过寄存器完成的,寄存器操作一般采用位运算或移位运算。
C语言提供了六种位运算操作符,分别是按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)、右移(>>)。
注意:下面案例使用的数字8和14均为unsigned char类型,因为有符号整数进行位运算后,其符号位可能会改变。
按位与(&)
按位与的运算符是“ & ”,它是一个双目运算符,它对运算符两边的操作数按位进行逻辑与运算,其运算规则是:0&0=0; 0&1=0; 1&0=0; 1&1=1,即:两位同时为1,结果才为1,否则为0。
例如:8 & 14 的结果是8。
数字8的二进制数是0000 1000,数字14的二进制数是00010 1110,两个二进制数每位进行逻辑与运算,结果是0000 1000。
按位与运算符在嵌入式开发中应用非常广泛,它可以用来判断寄存器中的某一位是否为 1,也可以用来对寄存器某些位进行清零操作。
假设一个8位寄存器AH的值为0x12,对应的二进制数为0001 0010,若需要判断第2个二进制位(从低位到高位)是否为1,可将AH与0x02进行与运算,若运算结果为0x02,则第2个二进制位为1,否则为0。
void main()
{
unsigned char AH = 0x12;
if( 0x02 == (AH & 0x02) )
{
printf("AH寄存器第2个二进制位为1");
}
else
{
printf("AH寄存器第2个二进制位为0");
}
}
上述代码段的条件判断也可以使用下面的语句:
if( AH & 0x02 )
因为0x02的二进制数位0000 0010,只有第2个二进制位为1,其它二进制位都为0,与AH进行与运算后,若AH第2个二进制位为1,则运算结果为0x02,否则运算结果为0,在C语言中,不为0的数值都为逻辑真。
按位或(|)
按位或的运算符是“|”,它是一个双目运算符,它对运算符两边的操作数按位进行逻辑或运算,其运算规则是:0|0=0; 0|1=1; 1|0=1; 1|1=1,即:两位只要有一个为1,其值为1,其它都为0。
例如:8 | 14 的结果是14。
按位异或(^)
按位异或的运算符是“^”,它是一个双目运算符,它对运算符两边的操作数按位进行逻辑异或运算,其运算规则是:0^0=0; 0^1=1; 1^0=1; 1^1=0,即:如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
例如:8 ^14 的结果是6。
按位取反(~)
按位取反的运算符是“~”,它是一个单目运算符,它对操作数按位进行逻辑非运算,其运算规则是::~0=1; ~1=0;,即:0变为1,1变为0。
例如:~8的结果是247。
左移(>>)
左移运算符是“>>”,它是双目运算符,它可以将运算符左边的操作数向左移动指定的位数,移动的位数由运算符右边的操作数给出,移动方向为从左到右,移动到左边界之外的多余二进制位会被丢弃,并从右边移入0。
例如:8 >>2 的结果是32。
从计算结果可以看出,左移 n 位相当于将这个数乘以 2 的 n 次方。
右移(<<)
右移运算符是“<<”,它是双目运算符,它可以将运算符左边的操作数向右移动指定的位数,移动的位数由运算符右边的操作数给出,移动方向为从右到左,移动到右边界之外的多余二进制位会被丢弃,并从左边移入0(无符号整数),对于有符号数整数,需要注意符号位的处理,如果移位的操作数是正数,右移时会在左边填充 0,如果是负数,右移时会在左边填充 1。
例如:8 >> 2 的结果是2。
从计算结果可以看出,右移 n 位相当于将这个数除以 2 的 n 次方。
位运算可以应用到位掩码技术,位掩码用于操作和检测一组二进制数据中的特定二进制位,通过掩码,我们可以方便地设置、清除或者翻转一组二进制数据中的特定二进制位。例如,我们可以定义一个掩码来提取一个字节的低4位。
#include
void printf_binary(unsigned char n);
void main()
{
unsigned char AH = 0xab;
unsigned char mask = 0x0f;
printf_binary(AH);
printf_binary(AH&mask);
}
void printf_binary(unsigned char n)
{
char i=0;
for(i=0; i< 8; i++ )
{
if(n&(0x80 > >i)){
printf("1");
}else
{
printf("0");
}
}
printf("n");
}
在上面的程序代码中,定义了printf_binary()函数,该函数将传入的参数n转换为二进制数并输出,函数内用到了循环语句,它可以重复执行相同的代码段,循环语句的语法后面还会讲述。
变量mask是我们定义的掩码 ,变量的值为0x0f,它的二进制表示为 00001111,mask与变量AH进行位与运算,运算的结果为变量AH的低4位。程序的输出结果见下图。
位运算一般在嵌入式开发中应用,用于配置单片机的寄存器,也会使用到一些高效的程序算法中。
7、运算符的优先级
C表达式可能存在多个运算符,运算符之间存在优先级的关系,级别高的运算符先执行运算,级别低的运算符后执行运算算,下表列出了运算符的优先级。表中优先级栏,数字越小优先级越高,运算符每个运算符用中文顿号分割。
表中小括号‘()’优先级最高,表达式含有小括号的,优先执行小括号的内容,如果包含多个小括号,执行顺序是从左到右。
在C语言中,运算符的优先级决定了表达式中运算执行的顺序。高优先级的运算符将在低优先级的运算符之前被执行。例如,乘法和除法运算符的优先级高于加法和减法运算符。
以下是如何判断C语言运算符优先级的步骤:
(1)了解C语言中的运算符类型。C语言中有多种运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符等。每种运算符都有不同的优先级。
(2)确定运算符的优先级。C语言中,运算符的优先级由高到低分为七个级别,下面列出了这些级别,以及相应的运算符:
- 后缀运算符:++、--
- 一元运算符:++、--、+、-、~、!
- 乘法 / 除法 / 取余:*、/%、
- 加法 / 减法:+、-
- 移位运算符:<<、>>
- 关系运算符:<、>、<=、>=
- 等于不等于:==、!=
- 位与运算符:&
- 位异或运算符:^
- 位或运算符:|
- 逻辑与运算符:&&
- 逻辑或运算符:||
- 条件运算符:? :
- 赋值运算符:=、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=
(3)根据优先级确定表达式的执行顺序。在复杂的表达式中,根据优先级确定运算执行的顺序非常重要。例如,在表达式a = b + c * d
中,乘法运算将在加法运算之前执行,因为乘法的优先级高于加法。
以下是一段根据C语言自增、自减、关系运算符、算术运算符优先级的示例代码,代码中包含了对这些运算符的用法的注释,并附带了示例和预期的输出结果。
#include
int main() {
int a = 5; // 初始化变量a为5
int b = 3; // 初始化变量b为3
// 算术运算符优先级: 加法 > 减法 > 乘法 > 除法 > 取余
// 关系运算符优先级: < > <= >= == !=
// 自增自减运算符优先级: ++ --
// 算术运算符示例
printf("a + b = %dn", a + b); // 输出: a + b = 8
printf("a - b = %dn", a - b); // 输出: a - b = 2
printf("a * b = %dn", a * b); // 输出: a * b = 15
printf("a / b = %dn", a / b); // 输出: a / b = 1
printf("a % b = %dn", a % b); // 输出: a % b = 2
// 关系运算符示例
printf("a > b? %sn", a > b ? "Yes" : "No"); // 输出: a > b? No
printf("a < b? %sn", a < b ? "Yes" : "No"); // 输出: a < b? Yes
printf("a >= b? %sn", a >= b ? "Yes" : "No"); // 输出: a >= b? Yes
printf("a <= b? %sn", a <= b ? "Yes" : "No"); // 输出: a <= b? No
printf("a == b? %sn", a == b ? "Yes" : "No"); // 输出: a == b? No
printf("a != b? %sn", a != b ? "Yes" : "No"); // 输出: a != b? Yes
// 自增自减运算符示例
printf("a++ + b = %dn", a++ + b); // 输出: a++ + b = 8 (这里,a先自增,然后和b相加,所以原来的a=5+1=6)
printf("a + b = %dn", a + b); // 输出: a + b = 8 (这里,a先和b相加,然后自增,所以原来的b=3)
printf("a-- + b = %dn", a-- + b); // 输出: a-- + b = 11 (这里,a先自减,然后和b相加,所以原来的a=6--)
printf("a + b = %dn", a + b); // 输出: a + b = 14 (这里,a先和b相加,然后自减,所以原来的b=3)
return 0;
}
上述代码展示了C语言中的算术运算符、关系运算符以及自增自减运算符的优先级和用法,每行代码前添加了详细的注释,运行这段代码应该没有错误,并会按照预期的方式输出结果。
评论
查看更多