浅识C语言中那些操作符(保证足够详细)

简介: 浅识C语言中那些操作符(保证足够详细)

在C语言中,有着众多的操作符,如果不能正确认识,那么在书写C语言代码时候,将会遇到这样那样的错误,甚至对于自己写的代码,都不知道bug在哪?更何况,去找bug呢??


因此,我们需要正确的去认识,并且知道每一个C语言操作符所代表的具体含义是什么!这样我们看待代码时候,才不会两眼抓瞎!


下面,笔者将带领大家认识一下,笔者所认识,及所感悟到操作符!!


1.算数操作符:


        +   -  *    /  %


在这里面,算术操作符,算是大家较为了解的操作符,毕竟每一个代码中,或多或少都会用到算术操作符!


但是我们运用时候,还要注意一下几点!


(1).除了%取除操作符之外,其他几个操作符,都可以应用于整数和浮点数


(2).对于/除法操作符,如果两个操作数都为整数,执行整数除法,而只要有小数(浮点数),执行的就是浮点数除法


(3).%取余操作符的两个操作数必须是整数!(很重要)


0a2653c851af460fa595bd959398a8f1.png


笔者亲测,这样将会进行报错!所以不能有这样的写法!


(4)./除法中,要想得到小数(浮点数),则必须保证在除数和被除数之间必须有一个小数(浮点数)


(5),我们还需要注意,加减乘除取余运算符之间的优先级!


2.移位操作符


《  左移位操作符    ;     》  右移位操作符


在这里,我们需要注意的是,移位操作符的操作数,只能是整数(小数,负数都不行),移位负数将没有意义


移位操作符:移动的是二进制位!


下面,我们需要浅浅介绍一下:二进制如何去表达??


如数值15:


在我们计算机中平常输入加使用的都是十进制形式!


在十进制中:15=1*10的一次幂+5*10的0次幂


在二进制中:15=1*2的3次幂+1*2的2次幂+1*2的一次幂+1*2的0次幂


在八进制中:15=1*8的1次幂+7*8的0次幂


至于其他的进制,由于篇幅原因,笔者将不再进行详细解答!


需要注意的是:10进制的表示为:0~9;


                         8进制的表示为0~7;


                          2进制的表示为0,1;


在二进制中:15=1*2的3次幂+1*2的2次幂+1*2的一次幂+1*2的0次幂


因此15的二进制表示为:00000000000000000000000000001111(一共32位)


原因为:15 是个整数,在C语言中可以存放在int 类型的变量中,而int类型的变量占4个字节(32个比特位)


上面我们已经了解到了进制的表达形式!但是,整型在计算机中的二进制的表达形式.............


整型的二进制的表示有三种:原码,反码,补码!


原码:直接根据数值写出的二进制序列就是原码


反码:原码的符号位不变,其余位按位取反就是反码


补码:反码+1就是补码


符号位:


                  开头的第一位就是符号位!


                  符号位位0:表示正数


                  符号位位1:表示负数


因此,对于15来说:(正数的原码,反码,补码相同)


00000000000000000000000000001111          15的原码


00000000000000000000000000001111           15的反码


00000000000000000000000000001111         15的补码


对于-15来说:(注意符号位的改变)


10000000000000000000000000001111            -15的原码


111111111111111111111111111111110000           -15的反码(原码的符号位不变,其余位按位取反就是反码)


111111111111111111111111111111110001           -15的补码(反码+1)


移位操作符:移动的是存储在内存中的补码!


当a=4时:


#include <stdio.h>
int main()
{
  int a = 4;
  //a的补码00000000000000000000000000000100
  int b = a << 1;
  //把a向左移动1位
  printf("a=%d  b=%d\n", a, b);
  return 0;
}

在这里,我们来看一下代码的运转结果:


0a2653c851af460fa595bd959398a8f1.png


对于这个结果:我们发现:移位运算符不改变原数值的大小!


00000000000000000000000000000100               4的(原码,反码,补码)


在移位运算符中,移动的是存储在内存中的补码!


6de278e6d6694ce5bb08e7e842b7e74b.png


因此,我们可以看出来,左移操作符规则:左边丢弃,右边补0;


当a=-4时候:


#include <stdio.h>
int main()
{
  int a = -4;
  //a的原码10000000000000000000000000000100
  int b = a << 1;
  //把a向左移动1位
  printf("a=%d  b=%d\n", a, b);
  return 0;
}

我们需要知道-4的原码,反码,补码


因此:


10000000000000000000000000000100           -4的原码


111111111111111111111111111111111011            -4的反码


111111111111111111111111111111111100             -4的补码


然后在根据刚才序列进行左移一位,得到的结果就是:


111111111111111111111111111111111000               补码


111111111111111111111111111111110111              反码(补码-1)


10000000000000000000000000001000              原码(反码符号位不变,其余位按位取反)


因此该数值为-8


0a2653c851af460fa595bd959398a8f1.png


因此,由上面两个代码,我们可以看出:左移操作符有乘2的效果!


注意,补码在移动过程中,如果将符号位移丢了,:那么,移丢就移丢,后面还能补回来!


右移操作符  《


当a=-4时候:


#include <stdio.h>
int main()
{
  int a = -4;
  //10000000000000000000000000000100 - 4的原码
    //111111111111111111111111111111111011 - 4的反码
  //111111111111111111111111111111111100 - 4的补码
  int b = a >> 1;
  //把a向右移动1位
  printf("a=%d  b=%d\n", a, b);
  return 0;
}


下面我们就a=-4来分析右移操作符:


0a2653c851af460fa595bd959398a8f1.png


对于右移操作符:左边空出来的一位:有两种补法!(在C语言中卖淫给出明显的绝对答案,只能根据编译器得来计算答案)


右移操作符:


           a.逻辑右移:


                         右边丢弃,左边补0;


           b.算术右移:(绝大多数是这样的)


                        右边丢弃,左边补原符号位(正数补0,负数补1)


6de278e6d6694ce5bb08e7e842b7e74b.png


对于该运算结果,结合二进制的右移结果,我们可以看出来用了算术右移!


因此,我们可以看出来,右移操作符有除2的效果!


3.位操作符(二进制的条件下)


&  按位与


|   按位或


^   按位异或


(1).   &   按位与


下面,笔者来结合此代码来进行分析:


#include <stdio.h>
int main()
{
  int a = 3;
  int b = -5;
  int c = a & b;
  printf("c=%d\n", c);
  return 0;
}

00000000000000000000000000000011          3的补码


10000000000000000000000000000101         -5的原码


111111111111111111111111111111111010          -5的反码


111111111111111111111111111111111011          -5的补码


因此,对于:


00000000000000000000000000000011          3的补码


111111111111111111111111111111111011          -5的补码


由&  按位与,可以得出:


00000000000000000000000000000011           补码(原码)


按位与规则:有0则为0,都1则为1


则打印结果为c=3


0a2653c851af460fa595bd959398a8f1.png


(2).      |    按位或


下面,笔者来结合此代码来进行分析(对上面代码进行浅浅改造)


#include <stdio.h>
int main()
{
  int a = 3;
  int b = -5;
  int c = a | b;
  printf("c=%d\n", c);
  return 0;
}

还是在补码上进行操作:


00000000000000000000000000000011          3的补码


111111111111111111111111111111111011          -5的补码


对于   |    按位或  ,可以得出:


11111111111111111111111111111111011            补码(负数)


则进补码-1到反码,在到原码的操作,可以得出该数字!


因此: |     按位或规则为:只要有1则为1,两个为0则为0;


最后的打印结果为:


0a2653c851af460fa595bd959398a8f1.png


(3)   ^   按位异或


下面,笔者来结合此代码来进行分析(对上面代码进行浅浅改造)


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

我们仍然需要3跟-5的补码:


00000000000000000000000000000011          3的补码


111111111111111111111111111111111011          -5的补码


由           ^    按位异或得出:


111111111111111111111111111111111000          补码(负数)


则进补码-1到反码,在到原码的操作,可以得出该数字!


因此   ^  按位异或的运算规则为:


相同为0,不同为1;


因此,该代码的运算结果为:


0a2653c851af460fa595bd959398a8f1.png


另外需要注意的是:


^   按位异或:


1,相同的数字按位异或结果为0;即3^3=0;


6de278e6d6694ce5bb08e7e842b7e74b.png


2,按位异或支持交换律;即3^5^6等于6^3^5;


12c3b7f3f8814309a195c64f051d4445.png


4.赋值运算符


=


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


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


下面介绍连续赋值


#include <stdio.h>
int mian()
{
  int a = 10;
  int b = 0;
  b = a = a + 3;
  printf("a=%d  b=%d\n", a, b);
  return 0;
}

在这里,b=a=a+3;是连续赋值的结果,最后的打印结果为:a=13,b=13;但是不建议这样去写。程序运转错误以后,没有办法去深入该表达式进行调试!


5.赋值运算符


+=            -=          *=          /=                %=          


>>=              <<=           &=          |=          ^=


6.单目操作符


!逻辑反操作符


-  负值


+  正值


&  取地址


sizeof   求操作符的类型长度(以字节为单位)


~    对一个数的二进制按位取反


--     前置,后置--


++  前置,后置++


*    间接访问操作符(解引用操作符)


(类型)   强制类型转化


1.    ! 逻辑反操作符


笔者将用下面代码来解析:


#include <stdio.h>
int main()
{
  int flag = 0;
  if (!flag)
  {
  printf("hehe\n");
  }
  return 0;
}

在if语句中,用了 !逻辑反操作符,


运转结果为:打印了hehe


0a2653c851af460fa595bd959398a8f1.png


但是笔者前面定义了flag=0,按照if语句中的,0表示假,是不会进入if语句,直接什么都不进行输出!但是最后的运转结果却是输出了hehe ,因此,!  逻辑反操作有取反的意思


2.  &   取地址操作符


&   取地址操作符  常常与      *    间接访问操作符(解引用操作符) 在指针中联用!


int a=10;
int *pa=&a;   //在这里int指a的类型,*指pa为指针变量
#include <stdio.h>
int main()
{
  int a = 10;
  int* pa = &a;
  printf("%d\n", a);
  printf("%d\n", *pa);        //由地址找到该数
  printf("%d\n", pa);            //打印pa的地址
  return 0;
}

代码的运转结果为:

0a2653c851af460fa595bd959398a8f1.png


*pa——》解引用操作符,最后得到a的值10;


pa——》得到a的地址


3.sizeof 操作数的类型长度(以字节为单位)


在多处都有涉及!


#include <stdio.h>
int main()
{
  short s = 10;
  int a = 2;
  printf("%d\n", sizeof(s = a + 5));          //2
  printf("s=%d\n", s);                        //10
  return 0;
}

借助此代码,笔者提醒大家,sizeof(表达式)   表达式内部不进行计算!


代码的运行结果为:short类型占2 个字节!在这里s 的值仍然为10;


0a2653c851af460fa595bd959398a8f1.png


注意数组传参时候:


#include <stdio.h>
void test1(int arr[])
{
  printf("%d\n", sizeof(arr));          //8
}
void test2(char ch[])
{
  printf("%d\n", sizeof(ch));             //8
}
int main()
{
  int arr[10] = { 0 };
  char ch[10] = { 0 };
  printf("%d\n", sizeof(arr));              //40
  printf("%d\n", sizeof(ch));           //10
  test1(arr);
  test2(ch);
  return 0;
}

在这里,我们需要注意的是:数组传参时候,传递的是首元素地址 ,占据4个(32位条件下)或者8个字节(64位条件下)


因此最后的打印结果为:


0a2653c851af460fa595bd959398a8f1.png


之前笔者就这这里栽过,因此需要读者强加注意!


4.数组名


数组名是数组首元素地址


但是有两个列外:


1.sizeof(数组名),在这里数组名表示的是整个数组,不是首元素地址


sizeof(数组名)计算的是整个数组的大小,单位是字节


2.   &数组名,在这里数组名表示的是整个数组,不是首元素地址,


&数组名,取出的是整数组的地址!


5.  ~   对一个数的二进制按位取反


下面笔者将用代码来进行讲解:


#include <stdio.h>
int main()
{
  int a = 0;
  printf("%d\n", ~a);
  return 0;
}

在这楼里,我们仍然需要最大a=0的二进制


00000000000000000000000000000000       0的补码


~      对一个数的二进制进行按位取反(包过符号位)


11111111111111111111111111111111           补码(负数)


11111111111111111111111111111110         反码(补码-1)


1000000000000000000000000001            原码(反码符号位不变,其余位按位取反)


即得到的结果为-1;


0a2653c851af460fa595bd959398a8f1.png


7,逻辑操作符


&&   逻辑与操作符


||      逻辑或操作符


下面笔者将用代码来进行讲解:


#include <stdio.h>
int main()
{
  int i = 0;
  int a = 0;
  int b = 2;
  int c = 3;
  int d = 4;
  i = a++ && ++b && d++;
  printf("a=%d  b=%d  c=%d   d=%d\n", a, b, c, d);
  return 0;
}

在该段代码中,用了前后置++运算符,因此我们需要注意:++i;先++,后输出,i++,先使用,后++;


&&   逻辑与操作符     只要前面有0,就不进行后面的运算


||      逻辑或操作符      只要前面有1,后面也就不用计算


0a2653c851af460fa595bd959398a8f1.png


对于a++先使用后++,因此,a=0,然后在进行后面.........;但是:&&   逻辑与操作符     只要前面有0,就不进行后面的运算,因此,后面的b,c,d,都不进行运算,然后a在++,然后输出a=1;


8.条件操作符(唯一一个三目运算符)


exp1?exp2:exp3


a>5?3:8


exp1用来判断条件是否成立,成立则用exp2,否则用exp3


9.逗号表达式


逗号表达式就是用逗号隔开的多个表达式;


逗号表达式从左到右依次执行(将前面的结果赋值给后面的字母相同的表达式),表达式的结果为最后一共表达式的结果;

#include <stdio.h>
int main()
{
  int a = 1;
  int b = 2;
  int c = (a > b, a = b + 10, a, b = a + 1);
  printf("a=%d  b=%d  c=%d\n", a, b, c);
  return 0;
}

在int c = (a > b, a = b + 10, a, b = a + 1);,我们可以看出来最后c的结果等于最后一个表达式b=a+1的结果!从前面依次计算表达式,可以得出a=12,b=13


运算结果为:

0a2653c851af460fa595bd959398a8f1.png


相关文章
|
4月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
78 0
|
4月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
276 0
|
2月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
44 10
|
2月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
169 1
|
2月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
182 0
|
4月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
46 6
|
4月前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
61 0
十一:《初学C语言》—  操作符详解(上)
|
5月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
45 1
五:《初学C语言》—  操作符
|
6月前
|
C语言
C语言逻辑操作符的短路问题
C语言逻辑操作符的短路问题
|
6月前
|
编译器 C语言
【C语言】:中移位操作符,位操作符详运算规则详解
【C语言】:中移位操作符,位操作符详运算规则详解
47 1