操作符详解(上篇)

前言

小伙伴们大家好,随着对c的不断学习今天我们将来学习操作符。在初始c语言中也介绍过操作符但也只是点到即可,今天我们将详细了解操作符。

操作符分类:

算术操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符

逗号表达式

下表引用,函数调用和结构成员

算术操作符

算术操作符都有哪些呢?让我们一起来看看吧。算术操作符包括:+ - * / %.在数学中乘号是X,但是在c语言中乘号是用*来表示的。同样的还有除号,也与数学中的写法不一样。同时还要注意的两个点,第一当除号两端都是整数时执行的是整数除法结果也是整数;除号有一端是小数时执行小数除法,所得的结果也是小数的形式。

第二个值得注意的点就是%,%是取模也被称之为取余。%的两端只能是整数不能是小数

当%的两端有一端是小数时,编译器会报错并提示有小数的一端非法

位移操作符

操作符移动的是二进制位,此时不得不先提整数的二进制表示形式。以int a = -3为例,int 是4个字节一个字节是八个比特位,所以此时a的二进制位有32位10000000000000000000000000000000011。整数的二进制表示形式有三种:原码,反码,补码。还是以a为例,此时a的原码为10000000000000000000000000000000011。反码:最高位不变,其余位进行按位取反,此时a的反码为11111111111111111111111111111100,。补码:在反码的基础上进行加1,此时a的补码为11111111111111111111111111111101.需要注意的是,正整数的原码反码补码都是一样的,而负整数的原码反码补码需要进行计算得出。可能有小伙伴要问了为啥我们非得要补码呢?原码不可以直接用吗?我们要求补码,是因为整数在内存中的存储是以补码的形式。

左移操作符<<

左移操作符移的是二进制的是二进制位

a的二进制位是000000000000000000000000000000011,把a的二进制位向左移一格,舍弃左边,右边补0,此时我们会得到b的二进制位000000000000000000000000000000110,b的值为6.上代码

简单归纳,左移操作符的使用方法是舍弃左边,右边补0.

右移操作符>>

左移操作符移的是二进制位,同样右移操作符移的也是二进制位。不过右移操作符分为两种:一种是逻辑右移,另一种是算术右移。逻辑右移:右边丢弃,左边直接用0填充。算术右移:右边丢弃,左边原来的符号位填充。在代码中是使用算术右移还是逻辑右移,这是由编译器决定的。不过一般都是使用算术右移。

从这里可以看出实现的是算术右移。那我们来分析一下倘若进行逻辑右移时又会有什么不同呢?让我们一起来看看吧。a=-3,其二进制位原码为10000000000000000000000000000011,反码:最高位不变,其余位进行按位取反得到11111111111111111111111111111100,补码:在反码的基础上加一得到11111111111111111111111111111101。当a按照算术右移来移动已为时,右边丢弃左边直接补0得到补码为:01111111111111111111111111111110 。补码减一取反得到原码:00000000000000000000000000000010此时得到a>>1的值为2.

不管是左移操作符还是右移操作符移动的都是整数,一定不能是小数。同时移动整数时一般移动的都是正整数。直接上代码来看看效果吧。当a左移的是一个负数时编译器会发出警告,同时运行结果是一个负数

这里我们需要注意,位移操作符移动的是整数且是正整数

位操作符

位操作符的分类:按位与&,按位或|,按位异或^。不管是按位与还是按位或还是按位异或中的位都是二进制位

按位与&

按位与简单来说就是,有0则0.用代码来理解吧

按位或|

按位或简单来说:有1则为1.依旧是用代码来理解吧

按位异或^

按位异或的使用方法:相同为0相异为1.依旧是用代码理解

来利用按位异或的知识来写一道题吧。题目要求为不使用临时变量来交换两个变量的值。

在之前的学习中交换两个变量的值我们会通过使用临时变量。但这题的要求是不使用临时变量。第一种解决方法

#include<stdio.h>
int main()
{
    int a = 3;
    int b = 5;
    printf("a=%d b=%d\n", a, b);
    a = a + b;//a=8
    b = a - b;//b=8-3=5;
    a = a - b;//a=8-5=3;
    printf("a=%d b=%d\n", a, b);

    return 0;
}

此时达到了交换变量值的目的,但是这种代码存在问题。当a和b的值非常大时,a+b的结果容易溢出。这种方法还是不太好。

第二种方法利用按位异或来进行解决

#include<stdio.h>
int main()
{
    int a = 3;
    int b = 5;
    printf("a=%d b=%d\n", a, b);
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    printf("a=%d b=%d\n", a, b);

    return 0;
}

利用按位异或,可以达到交换变量的效果。那可能又有小伙伴要问了,为啥会这样呢?接下来就让我们一起来分析分析吧

a的二进制位00000000000000000000000000000011

b的二进制位00000000000000000000000000000101

第一次按位异或得到a的值,这个值作为交换变量值的桥梁

a^b的结果为:00000000000000000000000000000110,a=a^b,此时a的值为6

再进行按位异或得到b的值

b=a^b::00000000000000000000000000000011 ,b的值为3

最后进行一次按位异或得到a的值

a=a^b:00000000000000000000000000000101,a的值为5.

赋值操作符

赋值操作符=,这里要注意区别与==。=是赋值操作符,==是判断相等。赋值操作符可以改变变量之前的值

   double salary = 10000.0;
   salary = 20000.0//使用赋值操作符进行赋值
   int weight = 110;
   weight = 90;//对体重不满意就可以赋值
   

复合赋值

+= : a= a+b;可以改成a+=b;

-= : a=a-b可以改成a -= b;

/=: a=a/b可以改为a/=b

%=: a=a%b可以改为a%=b;

>>=: a=a>>1改为a>>=1

<<+: a=a<<=1改为a<<=1

&= : a=a&b改为a&=b;

|= : a=a|b改为a|=b;

^=: a=a^b改为a^=b;

单目操作符

单目操作符的分类

!逻辑反操作符,++自增操作符,--自减操作符,&取地址操作符,*解引用操作符,~对一个二进制位进行按位取反,+正值,-负值,sizeof操作数类型大小(单位为字节),(类型)强制类型转化

!逻辑反操作符

!逻辑反操作符,例如a=1为真是,那么!a为假。倘若b=0时为假,那么!b为真

++自增操作符

++自增操作符分为前置++和后置++。前置++先加加再使用;后置加加,先使用再加加。直接上代码来康康它们的区别吧

int main()
{
    int a = 10;
    int b = a++;
    printf("a=%d,b=%d ", a, b);//a=11,b=10

    return 0;
}
int main()
{
    int a = 10;
    int b = ++a;
    printf("a=%d,b=%d ", a, b);//a=11,b=11

    return 0;
}

--自减操作符

--自减操作符也分为前置--和后置--.前置减减先减减再使用;后置减减,先使用再减减。上代码

int main()
{
    int a = 10;
    int b = --a;
    printf("a=%d,b=%d ", a, b);//a=9,b=9

    return 0;
}
int main()
{
    int a = 10;
    int b = a--;
    printf("a=%d,b=%d ", a, b);//b=10,a=9

    return 0;
}

&取地址操作符

&取地址操作符可以取出变量或者数组的地址,然后把地址放在指针变量中存储起来。

int main()
{
    int a = 10;
    int * pa = &a;
    printf("%p ", pa);

    return 0;
}

此时可以通过pa找到a的地址

int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9 };
    printf("%p ", &arr);

    return 0;
}

*解引用操作符

解引用操作符通常和取地址操作符搭配使用

int main()
{
    int a = 10;
    int* pa = &a;
    *pa = 20;
    printf("%d ", a);

    return 0;
}

把a的地址放在指针变量pa中,再通过解引用操作符对pa进行解引用操作。*pa就相当于是a

~对二进制位进行按位取反

直接上代码来康康吧

int main()
{
    int a = -3;//原码:10000000000000000000000000000011;
               //反码:11111111111111111111111111111100
               //补码:11111111111111111111111111111101
    a = ~a;  //~a;000000000000000000000000000000010
    printf("%d ", a);

    return 0;
}

sizeof操作数类型的大小

sizeof用来计算所占空间大小单位为字节,不但可以计算变量的大小还可以计算数组大小。让我们一起来看看代码吧

int main()
{
    int a = 10;
    printf("%d\n", sizeof(a));
    printf("%d\n", sizeof(int));
    int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
    printf("%d\n", sizeof(arr));
    printf("%d\n", sizeof(int[10]));
    
    return 0;
}

(类型)强制类型转化操作符

这种出现了一个警告,从double转化到int 可能丢失数据。此时有两种解决办法:第一种将int a 改为double a.把a的类型改为浮点型。第二种方法在10.0/3之前放一个(int)将结果转化为整形

以上就是操作符详解的上篇,欲知下事如何请听下回分解。操作符详解下篇正在准备中。

创作不易还望各位大佬们点赞,么么哒

  • 44
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 69
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值