C语言小白成长计划 二:运算符与表达式

运算符:

用来代表某种运算的符号,我们在进行运算的时候,操作数是可能有几种的,你可能会有1个操作数, 2个操作数 ,3个操作数。

几目运算符:该符号带了几个操作数。①单目运算符:1个操作数 ②双目运算符:2个操作数 ③三目运算符:3个操作数

在运算符的时候有一个方向:我们叫结合性从左边到右边,从右边到左边。

a + b 与 b + a在数学上面是一样的,但是c语言里面有点不一样

a + b;

int a;

int b;

int c = a + b;// c = b + a;在大多数情况里面还是和数学一样

但是有特别的例子:(i++) + (i + j) != (i + j) + (i++)实际上这两个式子是不一样的。ps:!表示非,!=表示不等于

在运算符里面是有优先级的:谁先算谁后算

单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 条件运算符 > 赋值运算符

> 逗号运算符

转载于百度

其实运算符我们可以不用特意去记,用得多了自然而然的就能分清了。

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

+ - * / % : 双目运算符

++ 和 -- :单目运算符

++和 --分为前后

这两个符号可以在我们的操作数的前后出现

在前面出现的时候我们叫前++/前--

后面出现的我们叫后++/后--

他们有区别:

在前面出现的时候:先变它的值,然后在取值

在后面出现的时候:先取值,然后再变它的值

int i = 3;
int a = ++i;//这时a = 4  i = 4
printf("%d",i);
int b = i++;//这时b = 4  i = 5
printf("%d",i);
int c = --i;//这时c = 4  i = 4
printf("%d",i);
int d = i--;//这时d = 4  i = 3
printf("%d",i);
printf("%d %d %d %d\n",a,b,c,d);//将abcd打印出来看看

双目算术运算符:

1 + 2;

/ : 在整数里面叫取整,小数里面叫除以。

% :两个操作数都必须是整数你才能操作,叫作求余。

5 / 4 : 取整,结果为1

5.0 / 4 :除以 结果1.25

int a = 5.0 / 4;

//结果1.25 会赋值给a,但是因为定义的a为整型,所以只保留整数部分,因此结果就是会将小数丢掉 为 1。于是a = 1。

int a = 5;

int b = 4;

double c = a / b; -> c最终的值为1.0

我这个时候是希望它变成除以,乘上一个小数就可以了

c = 1.0 * a / b;

我也可以叫计算机将a看成小数,强制转换 (类型)

c = (double)a / b;这时c的值是1.25;

c = (double)(a / b);这时c的值是1.0;这里相当于是先算将a / b取整,然后将结果看成是一个小数

打印出来看的时候记得是 %f ->打印浮点型

关系运算符,用来判断两者之间的关系的运算符:< > >= <= != ==

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

关系运算符是为了表示两者之间的关系的,此关系如果成立,那么值就是1,此关系不成立,那么值就是0

5 > 4 :它的值是1

5 < 4 :它的值为0

在我们的数学里面有这种写法:5 > 4 > 3:数学里面是完全成立的但是c语言里面这个式子就会有问题

5 > 4 > 3:这个关系是不成立的

5 > 4:关系成立 那么值为1

1 > 3:关系不成立 值为0

printf("%d %d %d\n",5 > 4,5 > 4 > 3,5 > (4 > 3));//输出为:1 0 1

5 > 4 > 3在数学上面的思维在c语言里面也经常会遇到,我们需要在c语言里面表达数学上面的这种思维:5 > 4 并且 4 > 3,并且:我们需要表达这种思想。

表达这种并且的思想:逻辑运算,进行逻辑运算运算的符号我们叫逻辑运算符

逻辑运算符:

! :逻辑非 单目运算符 真的变成假的假的变成真的

||:逻辑或 双目运算符 从左往右 或者

&&:逻辑与 双目运算符 从左往右 并且

1)逻辑与 -- 用AB表示:当A,B都为1(真)时,其值为1,否则为零。

2)逻辑或 -- 用 A+B 表示:当A,B都为0(假)时,其值为0,否则为1。

3)逻辑非 -- 用 A上'¯'表示,当A=0时,A的非为1,A=1时,A的非为0。

逻辑运算连接的式子我们叫逻辑表达式,这个表达式里面有两种值

1,真值(非0即为真,1)

2,假值(0)

逻辑运算符的值为真的话,那么它的值就是1

1为真,但是这里真即为1是不对的,因为5也是个真的。比如:

5 && 4 :因为左边非0为真,右边也是非0为真,这个表达式的值为1。

int a = 3;

int b = 4;

a && b :值为 1

!a && b : 值为0

!a || b :值为 1

c语言中的惰性运算:

int a,b,c,d,e,f;

a = 1,b = 2,c = 3,d = 4;

e = 2,f = 2;

(e = a > b) && (f = c > d);

printf("%d %d\n",e,f);//0 0 实际结果为0 2

上述的例子里面后面的f = c > d这个东西没有算这是c语言里面的惰性运算:当c语言知道这个玩意儿已经是一个定局了,后面是多少,就可以不用关心了。

a && b && c:

当a为假了之后,后面的b c不管是真还是假,结果都是假的,这个时候就不会去计算b c,只有a为真才会去计算b ,之后只有a b都是真的才会去计算c。

a || b || c

当a为真的时候,后面b c不管是真还是假结果都是真的,因此就不会去计算 b c,只有当a为假的时候才会去计算b ,之后当 a b都是假的时候才会去计算c。

感兴趣可以做这个练习:

闰年的规则:(1)能被4整除并且不能被100整除的年份就是闰年,例如1900它不是闰年。(2)能被400整除的年份也是闰年

我们需要写一个逻辑表达式来判断你的年份是否是闰年,小提示整除的概念:a % b如果余数为0表示为整除,不为0表示不能整除,依据值来判断真假:0为假 非0即为真。

参考代码:

#include <stdio.h>
 
int main() 
{
    int year,flag;//flag用来当做标记 
    printf("please input a year:\n");
    scanf("%d",&year);
    if( (year%4== 0) && ( (year%100)!=0 ) || year%400==0 )//能被4整除,但不能被100整除。或者能被400整除,flag=1
    {  
        flag=1;
    } 
    else//不是闰年,flag=0
    {    
        flag=0;
    }
    if(flag==1)
    {      
        printf("yes");
    }
    else
    {
        printf("no");
    }
 
    return 0;
}

位运算:

按照bit位来实现运算的一种运算符

&按位与

| 按位或

^按位异或

~按位取反

<<按位左移

>>按位右移

其中除了~按位取反是单目运算符以外,其他的都是双目运算符,结合性:从左往右,位运算在使用的时候只能是整数,在操作的时候必须将操作数变成bit,也就是一个bit对应一个bit来的。

~ :按位取反:将所有的bit位,1变成0 0变成1

int a = 1;(以前提过int为4个字节,一个字节8个bit)

00000000 00000000 00000000 00000001

~a =11111111 11111111 11111111 11111110

printf("%d\n",~a);11111111 11111111 11111111 11111110

~a是有符号的,因此要按照补码的形式进行转换

~a的最高bit是1,因此需要用负数的补码进行转换

先-1 得到 11111111 11111111 11111111 11111101

在取反 ~ 得到 00000000 00000000 00000000 00000010

添加- 号 得到最终值 -2

如果输出得是无符号的~a,那么printf("%u\n",~a);值为 2 ^ 32 - 2

char b = 1;

0000 0001

printf("%d\n",~b); ~b = 1111 1110

这时短赋长的问题解决,也就是前面的高位补符号位

11111111 11111111 11111111 11111110

结果跟上面还是一样,值为-2。

&:按位与,每一个bit都要参与运算

只有同时为高电平才会是高电平,只要有一个低电平了,那么就被拉低了

a = 3; 0000 0011

b = 5; 0000 0101

c = a & b; 0000 0001 得到c的值为 1

&------------

我需要将一个寄存器a,其它的bit不能动将bit3的功能关闭,bit3复位(将这个bit变成0),

以8位的寄存器来实现,bit位是从0开始的,将第nbit复位,其他的不变

a寄存器: xxxx xxxx

xxxx xxxx

&

1111 0111

------------------

xxxx 0xxx

x & 0 = 0;

x & 1 = x;

最终的操作 a = a & 0xf7 // a = a & (~(0x08))

a = a & (~(0x08))

-> a = a & (~(0x01 << n))

现在有一个变量 a = 0xff;它与上1的结果位:a & 1 -> 1111 1111 & 00000001 -> 1

假定a是一个字节,a = a & 0xff

| :按位或

基本规则:只要有高电平就是高电平

只有全部都是低电平才是低电平

我需要将一个寄存器a,其它的bit不能动,将bit3的功能打开,bit3置位(将这个bit变成1)以8位的寄存器来实现,bit位是从0开始的。

将第nbit置位:

a = a | 0x08;// a | 0000 1000

a = a | (0x01 << n);

一般都是1为功能打开,0为功能关闭

但是有特殊的情况,如:led灯有共阳(共阳极),共阴(共阴极)区别,共阳:1为灭 0为亮,共阴:1为亮 0为灭

^ : 按位异或,每一个bit都要操作

基本规则:相同为0,不同为1

x y x ^ y

0 0 0

1 0 1

0 1 1

1 1 0

2 ^ 4 ->数学上面是2的4次方,可以这么写,但是c语言里面是完全不一样的,因此我们c语言里面的,求次方,必须通过函数。

我需要将一个寄存器a,其它的bit不能动,将bit3的功能置为相反(如果为0就让他变成1,如果是1就让他变成0。

根据上面的真值表可以看出

x ^ 0 = x,

x ^ 1 = ~x;

a = a ^ 0x08;

其他bit全部取反,bit3不动。

a = a ^ 0xf7;//a ^ (~(0x08))

我需要将一个寄存器a,其它的bit不能动,第nbit取反

a = a ^ (0x01 << n);

练习:

有变量a b两个,可以用scanf进行输入

int a,b;

scanf("%d%d",&a,&b);//在终端输入的时候以空格或者回车做分隔

输入方式一:123 456 回车

方式二:123 回车 456 回车

不通过这个中间变量实现a b互换

假设a = 3 b = 4;

不知道你经过了一个什么操作

a = 4;

b = 3;

三种交换值的方法;代码奉上

#include <stdio.h>





int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("a = %d   b = %d\n",a,b);//这里是在做测试  看你的输入是否正确
    
    /*   (1) 带中间变量的交换两个变量的值
    int t;
    t = a;
    a = b;
    b = t;
    */
    
    /*      (2)不带中间变量
            这个方法是有bug的,
            a b的值可能会足够的大
            当两个值的和超过了其中一个变量的内存的最大值
            那么就会溢出,溢出之后就错了
    
    b = a + b;//b = 3 + 4 = 7;
    a = b - a;//a = b - a = 7 - 3 = 4;
    b = b - a;//a = b - a = 7 - 4 = 3;
    */

    //(3)异或交换值
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    
    
    
    
    printf("a = %d   b = %d\n",a,b);
    
    return 0;
}

a b在内存里面的状态都是bit

当a b的bit全部能互换位置,那么a b本身就互换了

x y x=x^y y=x^y x=x^y

0 0 0 0 0

1 1 0 1 1

0 1 1 0 1

1 0 1 1 0

<< :按位左移将前面的操作数左移后面制定的bit数

左移的规则:左移之后,右边空出来的bit自动变成0,也就是右边全部补0,当左边溢出的全部是0,并且不看符号,那么左移。

n个bit,那么实际上可以看出将这个数扩大

2 ^ n倍(2的n次方倍)

如:

a << 3;//将a左移3个bit

a = 5; //0000 0101

a = a << 3;//

a = 40

左移有两种:算术左移 逻辑左移,他们没有区别,左移之后,右边空出来的bit自动变成0,也就是右边全部补0。

>> :按位右移:分为逻辑右移以及算术右移。

逻辑右移:右边移出去的bit位直接丢弃,左边不管是有符号,还是没有符号都补0。

算术右移:右边移出去的bit位直接丢弃,左边如果是有符号的,左边补符号位,如果是没有符号的,左边补0

gcc/vc编译器默认有符号的时候用的是算术右移,这个时候就可能会出现结果不匹配的问题,c语言建议:将一个有符号的数进行右移的时候,为了保证,结果的一致性,请将这个有符号的强制转换成无符号的:

char a = 0x34;

a = a >> 3;//这个东西最好是不要做

//正常的做法 a = (unsigned char)a >> 3;

思考一个问题:

我有一个寄存器(8bit)a;,我要确定第3bit上面的功能是否打开,实际上就是要确定第3bit上面是1还是0,我们判断之前要知道一个事情:我能判断的只有真或者假

假的值为0 真的值为非0

当为假的时候我能确定所有的bit都是0

当为真的时候我是不能确定哪些bit是1的

因此我只能将我要判断的那个bit保留,其它的我要全部置0

a & (0x01 << 3) ->判断这个玩意儿的值是真的还是假的

如果是真值那么这个bit就是1

如果是假值那么这个bit就是0

我需要第3、4bit同时置位,a = a | (0x03 << 3)

赋值运算符:双目运算符 这个玩意儿的结合性是从右往左

赋值运算表表达式本身也会有自己的值,它的值为右边的值

a = b

a = b = 6;-> a = (b = 6)//b = 6本身是一个表达式 它也有自己的值 值为6

a = 6

这个表达式做完a b的值都是6

if(a == b)与if(a = b)的区别:

if(a == b)//如果a和b的值相等

if(a = b)//将b的值赋值给a,然后如果b为假/真

我们经常都是要表达如果a的值等于b那么记得一定是用a==b,不要搞混淆了

=号的左边是一个可写的地址,我们叫左值,=号的右边是一个可读的地址,我们叫右值

右值可以直接是常量等值,但是左值不行,它必须代表一个可写的地址

a = -1;

3 = a;//3不会是一个可写的地址 因此这个玩意儿语法有问题,错误。

我们的项目里面经常会判断两个东西的值是否相等:

a == b 用来判断两个东西的值是否相等的表达式

a = b;//合法 但是这个表达式是一个赋值表达式

if(a == b)

{}正确的

if(a = b)

{}也是正确的

上面的式子里面b是可以为常量的,因此我的代码就可以变成

if(a == 1)

{}正确的

if(a = 1)

{}也是正确的

我们在写代码的时候经常会将==少写一个,然后代码的问题就找不出来了,为了保证这种问题不出现

建议将上面的语句变成

if(1 == a)

{}正确的

你的等号又少写了一个

那么你的代码就会变成

if(1 = a)

{}不正确的 1不能是左值 这个时候编译的时候就直接报错

条件运算符: ? : 三目运算符

语法构成:

表达式1 ? 表达式2 : 表达式3;

如果表达式1的值为真,则整个表达式的值为表达式2的值

如果表达式1的值为假,则整个表达式的值为表达式3的值

练习:

输入两个整数,判断两个数谁大,输出大的那个值

max = (a > b ? a : b);

输出三个中的大值

int a,b,c;

scanf("%d%d%d",&a,&b,&c);

int max = a > b ? a : b;//取得两个之间的大值

//ab中间的大的值和c取比较

max = max > c ? max : c;//比较完 max就保存了abc中间的大的值

max = (max = (a > b ? a : b)) > c ? max : c;

a = 4 < 5 ? 5 > 6 : 7;//最终a的值为0(5 > 6的值)

逗号表达式:用,号连接在一起的表达式,双目运算符,优先级是最低的,从左往右结合;

表达式1,表达式2,表达式3,......表达式n,求值顺序为:先算表达式1,再算表达式2,再算表达式3.....最后算表达式n,逗号表达式本身是一个表达式,因此它这个表达式也会有值,它的值为表达式n的值,也就是最右边的那个表达式的值。

            int a = 3,b = 4;
            int c ;
            c = a = (b = 6,5 + 6);//经过这个表达式之后abc的值
           // a = 11  b = 6  c = 11

指针运算符:

*(指针); &(取地址)

求字节运算符

sizeof;

求它后面的那个玩意儿在内存里面所占的字节数

int a;

sizeof(a) ->看a在内存里面占几个字节,结果为4

练习:

写一个表达式,求a占的bit数,在我们的实际单片机操作里面,有的单片机内存不足,因此int有的时候只有2个字节,但是绝大多数的时候都是4个字节,现在我有如下代码:

int a;

int n = sizeof(int) * 8;//n为多少?

分量运算符:结构体天天用的

. 和 ->

下标运算符:

[] 在数组里面会看见

强制转换运算符:

语法构成:

(类型)表达式;

int a = 3;

char b = (char)a;//在c语言里面类型不匹配是不能赋值的

函数调用运算符:

做函数调用 scanf printf

小结:

表达式:在c语言里面就是为了表达某一个意思的式子,用运算符连接起来的式子我们就叫表达式

在c语言里面每一个表达式都会有值,这个值分为两种

1 真值:非0即为真

2 假值:0

特别是那种判断大小的,逻辑表达式...当判断为真的时候它的值是1

a > b : 这个表达式的值就只有两种

要么是成立:1

要么就是不成立:0

c语言里面的惰性运算一定要注意,当我们能确定这个玩意儿的最终的值了

那么就不会往后面算了。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值